Browse Source

remove libevent, ev_http. remove own thread handlign. switch to pEp::Webserver.

new_session_management
Roker 2 years ago
parent
commit
006cab02ee
5 changed files with 43 additions and 220 deletions
  1. +0
    -3
      server/Makefile
  2. +8
    -8
      server/Makefile.conf
  3. +14
    -25
      server/ev_server.cc
  4. +6
    -6
      server/ev_server.hh
  5. +15
    -178
      server/json-adapter.cc

+ 0
- 3
server/Makefile View File

@ -64,9 +64,6 @@ endif
ifdef ETPAN_LIB
EXTRA_LIB_PATHS:=$(EXTRA_LIB_PATHS)$(patsubst -L%,%,$(ETPAN_LIB)):
endif
ifdef EVENT_LIB
EXTRA_LIB_PATHS:=$(EXTRA_LIB_PATHS)$(patsubst -L%,%,$(EVENT_LIB)):
endif
ifdef GPGME_LIB
EXTRA_LIB_PATHS:=$(EXTRA_LIB_PATHS)$(patsubst -L%,%,$(GPGME_LIB)):
endif


+ 8
- 8
server/Makefile.conf View File

@ -60,11 +60,11 @@ WARN=placeholder
TARGET_ARCH=
ifeq ($(BUILD_FOR),Linux)
CXX=g++ -std=c++11 -pthread -fPIC
CXX=g++ -std=c++14 -pthread -fPIC
else ifeq ($(BUILD_FOR),Darwin)
# clang issues a warning when "-pthread" is used for linking. So, include it in CXXFLAGS, and not in CXX
# "c++" != "clang"
CXX=c++ -std=c++11 -fPIC
CXX=c++ -std=c++14 -fPIC
endif
HTML_DIR ?= "html"
@ -72,7 +72,7 @@ HTML_DIR ?= "html"
CPPFLAGS=-isystem $(GTEST_DIR)/include -DHTML_DIR=$(HTML_DIR)
ifeq ($(BUILD_FOR),Linux)
CXXFLAGS=-fstack-protector-all -fdiagnostics-color=always
CXXFLAGS=-fstack-protector-all # -fdiagnostics-color=always
ifdef WARN
CXXFLAGS+= -Wall
else
@ -84,7 +84,7 @@ ifeq ($(BUILD_FOR),Linux)
CXXFLAGS+= -O3 -DNDEBUG
endif
else ifeq ($(BUILD_FOR),Darwin)
CXXFLAGS=-pthread -fstack-protector-all -fcolor-diagnostics
CXXFLAGS=-pthread -fstack-protector-all # -fcolor-diagnostics
ifdef WARN
CXXFLAGS+= -Wall
else
@ -97,13 +97,13 @@ else ifeq ($(BUILD_FOR),Darwin)
endif
endif
CXXFLAGS+= -Ijson_spirit $(BOOST_INC) $(ENGINE_INC) $(ETPAN_INC) $(EVENT_INC) $(GPGME_INC) $(UUID_INC)
LDFLAGS+= $(BOOST_LIB) $(ENGINE_LIB) $(ETPAN_LIB) $(EVENT_LIB) $(GPGME_LIB) $(UUID_LIB)
CXXFLAGS+= -Ijson_spirit $(BOOST_INC) $(ENGINE_INC) $(ETPAN_INC) $(GPGME_INC) $(UUID_INC)
LDFLAGS+= $(BOOST_LIB) $(ENGINE_LIB) $(ETPAN_LIB) $(GPGME_LIB) $(UUID_LIB)
ifeq ($(BUILD_FOR),Linux)
LDLIBS+= -levent -lpEpEngine -lpEpAdapter -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread -Wl,-rpath-link="$(patsubst -L%,%,$(ETPAN_LIB))"
LDLIBS+= -lpEpEngine -lpEpAdapter -lboost_system -lboost_filesystem -lboost_program_options -lboost_thread -Wl,-rpath-link="$(patsubst -L%,%,$(ETPAN_LIB))"
GTEST_DIR=/usr/src/googletest/googletest/
else ifeq ($(BUILD_FOR),Darwin)
LDLIBS+= -levent -lpEpEngine -lpEpAdapter -lboost_system-mt -lboost_filesystem-mt -lboost_program_options-mt -lboost_thread-mt
LDLIBS+= -lpEpEngine -lpEpAdapter -lboost_system-mt -lboost_filesystem-mt -lboost_program_options-mt -lboost_thread-mt
endif
######### Google Test #########


+ 14
- 25
server/ev_server.cc View File

@ -1,4 +1,4 @@
#include <evhttp.h>
#include <pEp/webserver.hh>
#include "ev_server.hh"
#include "c_string.hh"
@ -58,13 +58,6 @@ std::string getBinaryPath()
}
void connection_close_cb(evhttp_connection* conn, void* arg)
{
JsonAdapter::getInstance().connection_close_cb();
}
// these are the pEp functions that are callable by the client
const FunctionMap functions = {
@ -168,7 +161,7 @@ const FunctionMap functions = {
} // end of anonymous namespace
void ev_server::sendReplyString(evhttp_request* req, const char* contentType, const std::string& outputText)
void ev_server::sendReplyString(pEp::Webserver::request& req, const char* contentType, const std::string& outputText)
{
auto* outBuf = evhttp_request_get_output_buffer(req);
if (!outBuf)
@ -192,7 +185,7 @@ void ev_server::sendReplyString(evhttp_request* req, const char* contentType, co
}
void ev_server::sendFile( evhttp_request* req, const std::string& mimeType, const fs::path& fileName)
void ev_server::sendFile(pEp::Webserver::request& req, const std::string& mimeType, const fs::path& fileName)
{
auto* outBuf = evhttp_request_get_output_buffer(req);
if (!outBuf)
@ -213,7 +206,7 @@ struct FileRequest
};
// catch-all callback
void ev_server::OnOtherRequest(evhttp_request* req, void*)
pEp::Webserver::response ev_server::OnOtherRequest(boost::cmatch match, const pEp::Webserver::request& req)
{
static const std::map<std::string, FileRequest > files =
{
@ -223,23 +216,19 @@ void ev_server::OnOtherRequest(evhttp_request* req, void*)
{ "/favicon.ico" , {"image/vnd.microsoft.icon", path_to_html / "json-test.ico"} },
};
const evhttp_uri* uri = evhttp_request_get_evhttp_uri(req);
const char* path = evhttp_uri_get_path(uri);
const char* uri_string = evhttp_request_get_uri(req);
Log() << Logger::Debug << "** Request: [" << uri_string << "] " << (path? " Path: [" + std::string(path) + "]" : "null path") << "\n";
const sv path = req.target(); // NB: is percent-encoded! does not relevant for the supported paths above.
Log() << Logger::Debug << "** Request: [" << request.method_string() << "] " << "Path: [" + path + "]";
try{
if(path)
const auto q = files.find(path);
if(q != files.end()) // found in "files" map
{
const auto q = files.find(path);
if(q != files.end()) // found in "files" map
{
Log() << Logger::Debug << "\t found file \"" << q->second.fileName.string() << "\", type=" << q->second.mimeType << ".\n";
sendFile( req, q->second.mimeType, q->second.fileName);
return;
}
sendFile( req, q->second.mimeType, q->second.fileName);
return;
}
const std::string reply = std::string("URI \"") + uri_string + "\" not found! "
+ (!path ? "NULL Path" : "Path: \"" + std::string(path) + "\"");
evhttp_send_error(req, HTTP_NOTFOUND, reply.c_str());
@ -256,7 +245,7 @@ void ev_server::OnOtherRequest(evhttp_request* req, void*)
// generate a JavaScript file containing the definition of all registered callable functions, see above.
void ev_server::OnGetFunctions(evhttp_request* req, void*)
pEp::Webserver::response ev_server::OnGetFunctions(boost::cmatch match, const pEp::Webserver::request& req)
{
static const auto& version = server_version();
static const std::string preamble =
@ -296,7 +285,7 @@ void ev_server::OnGetFunctions(evhttp_request* req, void*)
}
void ev_server::OnApiRequest(evhttp_request* req, void* obj)
pEp::Webserver::response ev_server::OnApiRequest(boost::cmatch match, const pEp::Webserver::request& req)
{
Logger L( Log(), "OnApiReq");
evbuffer* inbuf = evhttp_request_get_input_buffer(req);


+ 6
- 6
server/ev_server.hh View File

@ -5,8 +5,8 @@
#include <string>
#include <boost/filesystem/path.hpp>
#include <pEp/webserver.hh>
struct evhttp_request;
class Logger;
@ -14,22 +14,22 @@ class ev_server
{
public:
static
void sendReplyString(evhttp_request* req, const char* contentType, const std::string& outputText);
void sendReplyString(pEp::Webserver::request& req, const char* contentType, const std::string& outputText);
static
void sendFile( evhttp_request* req, const std::string& mimeType, const boost::filesystem::path& fileName);
void sendFile( pEp::Webserver::request& req, const std::string& mimeType, const boost::filesystem::path& fileName);
// catch-all callback. Used by demo html & JavaScript client to deliver static HTML & JS files
static
void OnOtherRequest(evhttp_request* req, void*);
pEp::Webserver::response OnOtherRequest(boost::cmatch match, const pEp::Webserver::request& req);
// generate a JavaScript file containing the definition of all registered callable functions, see above.
static
void OnGetFunctions(evhttp_request* req, void*);
pEp::Webserver::response OnGetFunctions(boost::cmatch match, const pEp::Webserver::request& req);
// handles calls to the JSON-RPC API
static
void OnApiRequest(evhttp_request* req, void* obj);
pEp::Webserver::response OnApiRequest(boost::cmatch match, const pEp::Webserver::request& req);
// should be set before any of the methods above is called, due to static initializers use that value,
// so changing it later might be useless.


+ 15
- 178
server/json-adapter.cc View File

@ -5,7 +5,7 @@
#include <thread>
#include <cstdint>
#include <vector>
#include <evhttp.h>
#include <pEp/webserver.hh>
#include <string>
#include <set>
@ -43,7 +43,6 @@ namespace {
std::string BaseUrl = "/ja/0.1/";
int SrvThreadCount = 3;
const std::string CreateSessionUrl = BaseUrl + "createSession";
const std::string GetAllSessionsUrl = BaseUrl + "getAllSessions";
@ -52,15 +51,6 @@ const std::string ApiRequestUrl = BaseUrl + "callFunction";
const uint64_t Guard_0 = 123456789;
const uint64_t Guard_1 = 987654321;
auto ThreadDeleter = [](std::thread* t)
{
auto& session_registry = JsonAdapter::getSessionRegistry();
session_registry.remove(t->get_id());
};
typedef std::unique_ptr<std::thread, decltype(ThreadDeleter)> ThreadPtr;
typedef std::vector<ThreadPtr> ThreadPool;
typedef std::recursive_mutex Mutex;
typedef std::unique_lock<Mutex> Lock;
@ -83,8 +73,6 @@ JsonAdapter* JsonAdapter::singleton = nullptr;
struct JsonAdapter::Internal
{
std::unique_ptr<event_base, decltype(&event_base_free)> eventBase = {nullptr, &event_base_free};
std::unique_ptr<evhttp, decltype(&evhttp_free)> evHttp = {nullptr, &evhttp_free};
std::unique_ptr<SessionRegistry> session_registry{};
std::string address;
std::string token;
@ -94,16 +82,14 @@ struct JsonAdapter::Internal
unsigned start_port = 0;
unsigned end_port = 0;
unsigned port = 0;
std::unique_ptr<pEp::Webserver> webserver;
inject_sync_event_t inject_sync_event = nullptr;
unsigned request_count = 0;
evutil_socket_t sock = -1;
bool running = false;
bool silent = false;
bool ignore_session_error = false;
bool deliver_html = true;
ThreadPool threads;
// PEP_SESSION session = nullptr;
explicit Internal()
: Log("JAI")
@ -114,32 +100,7 @@ struct JsonAdapter::Internal
~Internal()
{
// if(session)
// pEp::call_with_lock(&release, session);
// session=nullptr;
}
static
void requestDone(evhttp_request* req, void* userdata)
{
// Hum, what is to do here?
}
/*
static
PEP_STATUS deliverRequest(const std::string& uri, evhttp_connection* connection, const js::Object& request)
{
const std::string request_s = js::write(request, js::raw_utf8);
evhttp_request* ereq = evhttp_request_new( &requestDone, nullptr ); // ownership goes to the connection in evhttp_make_request() below.
evhttp_add_header(ereq->output_headers, "Content-Length", std::to_string(request_s.length()).c_str());
auto output_buffer = evhttp_request_get_output_buffer(ereq);
evbuffer_add(output_buffer, request_s.data(), request_s.size());
const int ret = evhttp_make_request(connection, ereq, EVHTTP_REQ_POST, uri.c_str() );
return (ret == 0) ? PEP_STATUS_OK : PEP_UNKNOWN_ERROR;
}
*/
void makeAndDeliverRequest(const char* function_name, const js::Array& params)
{
@ -195,7 +156,6 @@ ServerVersion JsonAdapter::version()
PEP_STATUS JsonAdapter::messageToSend(message* msg)
{
// JsonAdapter* ja = static_cast<JsonAdapter*>(obj);
js::Value v{to_json(msg)};
getInstance().i->makeAndDeliverRequest("messageToSend", js::Array{ std::move(v) } );
return PEP_STATUS_OK;
@ -204,7 +164,6 @@ PEP_STATUS JsonAdapter::messageToSend(message* msg)
PEP_STATUS JsonAdapter::notifyHandshake(pEp_identity* self, pEp_identity* partner, sync_handshake_signal sig)
{
// JsonAdapter* ja = static_cast<JsonAdapter*>(obj);
js::Array param_array;
param_array.emplace_back( to_json(self) );
param_array.emplace_back( to_json(partner) );
@ -219,13 +178,7 @@ JsonAdapter::JsonAdapter()
, i(new Internal{})
, guard_1(Guard_1)
{
i->eventBase.reset(event_base_new());
if (!i->eventBase)
throw std::runtime_error("Failed to create new base_event.");
i->evHttp.reset( evhttp_new(i->eventBase.get()) );
if (!i->evHttp)
throw std::runtime_error("Failed to create new evhttp.");
// nothing to do here.
}
@ -265,99 +218,20 @@ void JsonAdapter::prepare_run(const std::string& address, unsigned start_port, u
i->start_port = start_port;
i->end_port = end_port;
// Log() << "ThreadFunc: thread id " << std::this_thread::get_id() << ". \n Registry: " << to_string( session_registry );
unsigned port_ofs = 0;
try_next_port:
auto* boundSock = evhttp_bind_socket_with_handle(i->evHttp.get(), i->address.c_str(), i->start_port + port_ofs);
if (!boundSock)
// pEp::Webserver does not support port probing, yet.
i->webserver = std::make_unique<pEp::Webserver>(pEp::net::ip::address::from_string(address), start_port, "");
i->webserver->add_url_handler(ApiRequestUrl, ev_server::OnApiRequest);
if(i->deliver_html)
{
++port_ofs;
if(i->start_port + port_ofs > i->end_port)
{
throw std::runtime_error("Failed to bind server socket: "
"No free port between " + std::to_string(i->start_port) + " and " + std::to_string(i->end_port)
);
}
goto try_next_port;
i->webserver->add_url_handler("/pEp_functions.js", ev_server::OnGetFunctions);
i->webserver->add_generic_url_handler(ev_server::OnOtherRequest);
}
if ((i->sock = evhttp_bound_socket_get_fd(boundSock)) == -1)
throw std::runtime_error("Failed to get server socket for next instance.");
i->port = i->start_port + port_ofs;
i->port = i->start_port;
i->token = create_security_token(i->address, i->port, BaseUrl);
Log() << "Bound to port " << i->port << ", sec_token=\"" << i->token << "\", sock=" << i->sock << ".";
}
void JsonAdapter::threadFunc()
{
Logger L("JA:tF");
try
{
const auto id = std::this_thread::get_id();
L << Logger::Info << " +++ Thread starts: isRun=" << i->running << ", id=" << id << ". +++";
PEP_SESSION session = i->session_registry->get(id);
(void)session; // not used, yet.
std::unique_ptr<event_base, decltype(&event_base_free)> eventBase(event_base_new(), &event_base_free);
if (!eventBase)
throw std::runtime_error("Failed to create new base_event.");
std::unique_ptr<evhttp, decltype(&evhttp_free)> evHttp(evhttp_new(eventBase.get()), &evhttp_free);
if (!evHttp)
throw std::runtime_error("Failed to create new evhttp.");
evhttp_set_cb(evHttp.get(), ApiRequestUrl.c_str() , ev_server::OnApiRequest , this);
if(i->deliver_html)
{
evhttp_set_cb(evHttp.get(), "/pEp_functions.js" , ev_server::OnGetFunctions , this);
evhttp_set_gencb(evHttp.get(), ev_server::OnOtherRequest, nullptr);
}
if (i->sock == -1) // no port bound, yet
{
throw std::runtime_error("You have to call prepare_run() before run()!");
}
else
{
L << Logger::Info << "\tnow I call evhttp_accept_socket()...";
if (evhttp_accept_socket(evHttp.get(), i->sock) == -1)
throw std::runtime_error("Failed to accept() on server socket for new instance.");
}
while(i->running)
{
#ifdef EVLOOP_NO_EXIT_ON_EMPTY
// for libevent 2.1:
event_base_loop(eventBase.get(), EVLOOP_NO_EXIT_ON_EMPTY);
#else
// for libevent 2.0:
event_base_loop(eventBase.get(), 0);
#endif
}
Lock L{_mtx};
i->eventListener.erase( std::this_thread::get_id() );
}
catch (const std::exception& e)
{
L << Logger::Error << " +++ std::exception in ThreadFunc: " << e.what();
initExcept = std::current_exception();
Lock L{_mtx};
i->eventListener.erase( std::this_thread::get_id() );
}
catch (...)
{
L << Logger::Crit << " +++ UNKNOWN EXCEPTION in ThreadFunc +++ ";
initExcept = std::current_exception();
Lock L{_mtx};
i->eventListener.erase( std::this_thread::get_id() );
}
L << Logger::Info << " +++ Thread exit? isRun=" << i->running << ", id=" << std::this_thread::get_id() << ". initExcept is " << (initExcept?"":"not ") << "set. +++";
Log() << "Bound to port " << i->port << ", sec_token=\"" << i->token << "\".";
}
@ -371,24 +245,7 @@ try
L << Logger::Debug << "Registry:\n" << i->session_registry->to_string();
i->running = true;
for(int t=0; t<SrvThreadCount; ++t)
{
L << Logger::Info << "Start Thread #" << t << "...";
ThreadPtr thread(new std::thread(staticThreadFunc, this), ThreadDeleter);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (initExcept)
{
thread->join();
i->running = false;
std::rethrow_exception(initExcept);
}
i->threads.push_back(std::move(thread));
}
L << Logger::Debug << "All " << SrvThreadCount << " thread(s) started:";
for(const auto& t:i->threads)
{
L << Logger::Debug << "\tthread_id()=" << t->get_id() << ".";
}
i->webserver->run();
}
catch (std::exception const &e)
{
@ -415,22 +272,7 @@ void JsonAdapter::shutdown(timeval* t)
check_guard();
Log() << "JS::shutdown() was called.";
i->running = false;
/**** FIXME: proper shutdown!
const int ret = event_base_loopexit(i->eventBase.get(), t);
if(ret!=0)
{
throw std::runtime_error("JsonAdapter::shutdown() failed.");
}
****/
Log() << "JS::shutdown(): event_base loop is finished.\n";
Log() << "\t there are " << i->threads.size() << " threads remaining in the threadpool.";
for(const auto& t : i->threads)
{
Log() << "\t\tjoin() on id=" << t->get_id() << "....";
t->join();
}
i->threads.clear();
i->webserver->shutdown();
}
@ -449,12 +291,7 @@ bool JsonAdapter::verify_security_token(const std::string& s) const
void JsonAdapter::augment(json_spirit::Object& returnObject)
{
check_guard();
/*
PEP_SESSION session = this->i->session;
auto errorstack = get_errorstack(session);
returnObject.emplace_back( "errorstack", to_json(errorstack) );
clear_errorstack(session);
*/
// nothing to do anymore.
}


Loading…
Cancel
Save