Skip to content

Commit 6d66c4f

Browse files
committed
Enable REST/UDP proxies to use HTTP connection
Also, fix an eventual race condition accessing: - Ecf::state_change_no_ and Ecf::state_modify_no_ Apart from making these global (instead of thread_local), the Http library is restricted to the use of a single thread Re ECFLOW-1957
1 parent bb21a5e commit 6d66c4f

File tree

21 files changed

+648
-112
lines changed

21 files changed

+648
-112
lines changed

libs/CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,7 @@ set(srcs
479479
# Server -- Headers
480480
server/src/ecflow/server/BaseServer.hpp
481481
server/src/ecflow/server/CheckPtSaver.hpp
482+
server/src/ecflow/server/HttpServer.hpp
482483
server/src/ecflow/server/NodeTreeTraverser.hpp
483484
server/src/ecflow/server/PeriodicScheduler.hpp
484485
server/src/ecflow/server/Server.hpp
@@ -491,6 +492,7 @@ set(srcs
491492
# Server -- Sources
492493
server/src/ecflow/server/BaseServer.cpp
493494
server/src/ecflow/server/CheckPtSaver.cpp
495+
server/src/ecflow/server/HttpServer.cpp
494496
server/src/ecflow/server/NodeTreeTraverser.cpp
495497
server/src/ecflow/server/PeriodicScheduler.cpp
496498
server/src/ecflow/server/Server.cpp
@@ -569,8 +571,10 @@ ecbuild_add_library(
569571
$<$<BOOL:${OPENSSL_FOUND}>:OpenSSL::SSL>
570572
$<$<NOT:$<BOOL:${APPLE}>>:crypt>
571573
Threads::Threads
572-
DEFINITIONS
574+
$<$<BOOL:${ZLIB_FOUND}>:ZLIB::ZLIB>
575+
PUBLIC_DEFINITIONS
573576
CMAKE
577+
$<$<BOOL:${ZLIB_FOUND}>:ECF_HTTP_COMPRESSION>
574578
)
575579
target_clangformat(ecflow_all)
576580

libs/base/src/ecflow/base/HttpClient.cpp

+20-8
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
#include "ecflow/core/Converter.hpp"
1919

2020
HttpClient::HttpClient(Cmd_ptr cmd_ptr, const std::string& host, const std::string& port, int timeout)
21-
: stopped_(false),
22-
host_(host),
21+
: host_(host),
2322
port_(port),
2423
client_(host, ecf::convert_to<int>(port)) {
2524

@@ -34,16 +33,29 @@ void HttpClient::run() {
3433
std::string outbound;
3534
ecf::save_as_string(outbound, outbound_request_);
3635

37-
auto result = client_.Post("/v1/ecflow", outbound, "application/json");
38-
auto response = result.value();
39-
40-
ecf::restore_from_string(response.body, inbound_response_);
41-
};
36+
auto result = client_.Post("/v1/ecflow", outbound, "application/json");
37+
if (result) {
38+
auto response = result.value();
39+
ecf::restore_from_string(response.body, inbound_response_);
40+
}
41+
else {
42+
status_ = result.error();
43+
reason_ = httplib::to_string(status_);
44+
}
45+
}
4246

4347
bool HttpClient::handle_server_response(ServerReply& server_reply, bool debug) const {
4448
if (debug) {
4549
std::cout << " Client::handle_server_response" << std::endl;
4650
}
4751
server_reply.set_host_port(host_, port_); // client context, needed by some commands, ie. SServerLoadCmd
48-
return inbound_response_.handle_server_response(server_reply, outbound_request_.get_cmd(), debug);
52+
53+
if (status_ == httplib::Error::Success) {
54+
return inbound_response_.handle_server_response(server_reply, outbound_request_.get_cmd(), debug);
55+
}
56+
else {
57+
std::stringstream ss;
58+
ss << "HttpClient::handle_server_response: Error: " << status_ << " " << reason_;
59+
throw std::runtime_error(ss.str());
60+
}
4961
}

libs/base/src/ecflow/base/HttpClient.hpp

+10-6
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
#ifndef ecflow_base_HttpClient_HPP
1212
#define ecflow_base_HttpClient_HPP
1313

14+
#define CPPHTTPLIB_THREAD_POOL_COUNT 1
15+
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
16+
#define CPPHTTPLIB_ZLIB_SUPPORT 1
17+
1418
#include <httplib.h>
1519

1620
#include "ecflow/base/ClientToServerRequest.hpp"
1721
#include "ecflow/base/Connection.hpp"
1822
#include "ecflow/base/ServerToClientResponse.hpp"
1923

2024
///
21-
/// \brief This class acts as the client part. ( in client/server architecture)
22-
///
23-
/// \note The plug command can move a node to another server hence the server
24-
/// itself will NEED to ACT as a client. This is why client lives in Base and
25-
/// not the Client project
25+
/// \brief This class acts as an HTTP client
2626
///
2727

2828
class HttpClient {
@@ -38,10 +38,14 @@ class HttpClient {
3838
bool handle_server_response(ServerReply&, bool debug) const;
3939

4040
private:
41-
bool stopped_;
4241
std::string host_; /// the servers name
4342
std::string port_; /// the port on the server
4443
httplib::Client client_;
44+
45+
httplib::Response response_;
46+
httplib::Error status_ = httplib::Error::Success;
47+
std::string reason_ = "";
48+
4549
ClientToServerRequest outbound_request_; /// The request we will send to the server
4650
ServerToClientResponse inbound_response_; /// The response we get back from the server
4751
};

libs/client/src/ecflow/client/ClientEnvironment.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ void ClientEnvironment::read_environment_variables() {
245245

246246
ecf::environment::get(ecf::environment::ECF_TRYNO, task_try_num_);
247247

248+
std::string host_protocol;
249+
ecf::environment::get(ecf::environment::ECF_HOST_PROTOCOL, host_protocol);
250+
if (host_protocol == "HTTP" || host_protocol == "HTTPS") {
251+
http_ = true;
252+
}
253+
248254
ecf::environment::get("ECF_HOSTFILE", host_file_);
249255

250256
ecf::environment::get(ecf::environment::ECF_RID, remote_id_);

libs/client/src/ecflow/client/ClientInvoker.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@
8484

8585
#include "ecflow/base/HttpClient.hpp"
8686

87+
#if defined(ADD)
88+
// undefine to avoid conflict with /usr/include/arpa/nameser_compat.h #define ADD ns_uop_add
89+
#undef ADD
90+
#endif
91+
#if defined(STATUS)
92+
// undefine to avoid conflict with /usr/include/arpa/nameser_compat.h #define STATUS ns_o_status
93+
#undef STATUS
94+
#endif
95+
8796
using namespace std;
8897
using namespace ecf;
8998
using namespace boost::posix_time;

libs/core/src/ecflow/core/Ecf.cpp

+2-16
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
bool Ecf::server_ = false;
1414
bool Ecf::debug_equality_ = false;
1515
unsigned int Ecf::debug_level_ = 0;
16-
thread_local Ecf::atomic_counter_t Ecf::state_change_no_ = 0;
17-
thread_local Ecf::atomic_counter_t Ecf::modify_change_no_ = 0;
16+
Ecf::atomic_counter_t Ecf::state_change_no_ = 0;
17+
Ecf::atomic_counter_t Ecf::modify_change_no_ = 0;
1818
bool DebugEquality::ignore_server_variables_ = false;
1919

2020
const char* Ecf::SERVER_NAME() {
@@ -80,20 +80,6 @@ const std::string& Ecf::URL() {
8080
return URL;
8181
}
8282

83-
Ecf::counter_t Ecf::incr_state_change_no() {
84-
if (server_) {
85-
return ++state_change_no_;
86-
}
87-
return state_change_no_;
88-
}
89-
90-
Ecf::counter_t Ecf::incr_modify_change_no() {
91-
if (server_) {
92-
return ++modify_change_no_;
93-
}
94-
return modify_change_no_;
95-
}
96-
9783
// =======================================================
9884

9985
EcfPreserveChangeNo::EcfPreserveChangeNo()

libs/core/src/ecflow/core/Ecf.hpp

+27-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
///
1717

1818
#include <atomic>
19+
#include <iostream>
1920
#include <string>
2021

2122
/**
@@ -47,14 +48,32 @@ class Ecf {
4748
const Ecf& operator=(const Ecf&) = delete;
4849

4950
/// Increment and then return state change no
50-
static counter_t incr_state_change_no();
51-
static counter_t state_change_no() { return state_change_no_; }
52-
static void set_state_change_no(counter_t x) { state_change_no_ = x; }
51+
static counter_t incr_state_change_no() {
52+
if (server_) {
53+
++state_change_no_;
54+
}
55+
return state_change_no_;
56+
}
57+
static counter_t state_change_no() {
58+
return state_change_no_;
59+
}
60+
static void set_state_change_no(counter_t x) {
61+
state_change_no_ = x;
62+
}
5363

5464
/// The modify_change_no_ is used for node addition and deletion and re-ordering
55-
static counter_t incr_modify_change_no();
56-
static counter_t modify_change_no() { return modify_change_no_; }
57-
static void set_modify_change_no(counter_t x) { modify_change_no_ = x; }
65+
static counter_t incr_modify_change_no() {
66+
if (server_) {
67+
++modify_change_no_;
68+
}
69+
return modify_change_no_;
70+
}
71+
static counter_t modify_change_no() {
72+
return modify_change_no_;
73+
}
74+
static void set_modify_change_no(counter_t x) {
75+
modify_change_no_ = x;
76+
}
5877

5978
/// Returns true if we are on the server side.
6079
/// Only in server side do we increment state/modify numbers
@@ -91,8 +110,8 @@ class Ecf {
91110
static bool server_;
92111
static bool debug_equality_;
93112
static unsigned int debug_level_;
94-
static thread_local atomic_counter_t state_change_no_;
95-
static thread_local atomic_counter_t modify_change_no_;
113+
static atomic_counter_t state_change_no_;
114+
static atomic_counter_t modify_change_no_;
96115
};
97116

98117
/// Make sure the Ecf number don't change

libs/rest/src/ecflow/http/HttpServer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ void HttpServer::parse_args(int argc, char** argv) const {
8484
opts.no_ssl = true;
8585
}
8686
if (backend_http) {
87-
opts.host_protocol = "http";
87+
opts.host_protocol = "HTTPS";
8888
}
8989

9090
setenv("ECF_HOST", opts.ecflow_host.c_str(), 1);

libs/rest/test/TestApiV1.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010

1111
#ifdef ECF_OPENSSL
12-
#define CPPHTTPLIB_OPENSSL_SUPPORT
12+
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
1313
#endif
1414

15+
#define CPPHTTPLIB_THREAD_POOL_COUNT 1
16+
#define CPPHTTPLIB_ZLIB_SUPPORT 1
17+
1518
#include <httplib.h>
1619

1720
#include <boost/test/unit_test.hpp>

libs/server/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ ecbuild_add_executable(
2020
ecflow_all
2121
$<$<BOOL:${OPENSSL_FOUND}>:OpenSSL::SSL>
2222
Threads::Threads
23+
$<$<BOOL:${ZLIB_FOUND}>:ZLIB::ZLIB>
24+
DEFINITIONS
25+
$<$<BOOL:${ZLIB_FOUND}>:ECF_HTTP_COMPRESSION>
2326
)
2427
target_clangformat(ecflow_server)
2528

0 commit comments

Comments
 (0)