Skip to content

Commit e778381

Browse files
authored
Merge pull request #608 from mtconnect/fix_remote_host_logging_in_rest_sink
2 parents 708116f + 170ff77 commit e778381

49 files changed

Lines changed: 415 additions & 280 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CMakeLists.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set(AGENT_VERSION_MAJOR 2)
33
set(AGENT_VERSION_MINOR 7)
44
set(AGENT_VERSION_PATCH 0)
5-
set(AGENT_VERSION_BUILD 9)
5+
set(AGENT_VERSION_BUILD 10)
66
set(AGENT_VERSION_RC "")
77

88
# This minimum version is to support Visual Studio 2019 and C++ feature checking and FetchContent

‎src/mtconnect/agent.cpp‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,14 @@ namespace mtconnect {
461461
{
462462
auto printer = dynamic_cast<printer::XmlPrinter *>(m_printers["xml"].get());
463463
auto device = m_xmlParser->parseDevice(deviceXml, printer);
464-
loadDevices({device}, source);
464+
if (device == nullptr)
465+
{
466+
LOG(error) << "Error loading device: " << deviceXml;
467+
}
468+
else
469+
{
470+
loadDevices({device}, source);
471+
}
465472
}
466473
catch (runtime_error &e)
467474
{

‎src/mtconnect/configuration/agent_config.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ namespace mtconnect::configuration {
522522
}
523523

524524
ptree empty;
525-
auto logger = config.get_child_optional("logger_config").value_or(empty);
525+
auto logger = config.get_child_optional("logger_config")
526+
.value_or(config.get_child_optional("logging").value_or(empty));
526527

527528
const string defaultFileName = channelName + ".log";
528529
const string defaultArchivePattern = channelName + "_%Y-%m-%d_%H-%M-%S_%N.log";

‎src/mtconnect/parser/xml_parser.cpp‎

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -258,33 +258,87 @@ namespace mtconnect::parser {
258258
DevicePtr XmlParser::parseDevice(const std::string &deviceXml, printer::XmlPrinter *aPrinter)
259259
{
260260
DevicePtr device;
261-
262-
using namespace boost::adaptors;
263-
using namespace boost::range;
264-
265261
std::unique_lock lock(m_mutex);
266262

263+
// Parse the device XML unti an in memory doc and then see if we have a root MTConnectDevices
264+
// node or a Device node. If devices, then we need to find the first device and then use the
265+
// entity parser to parse the device. We then log any errors.
266+
267+
xmlDocPtr doc = nullptr;
267268
try
268269
{
269-
entity::ErrorList errors;
270-
auto entity = entity::XmlParser::parse(Device::getRoot(), deviceXml, errors);
271-
if (errors.size() > 0)
270+
xmlInitParser();
271+
xmlSetGenericErrorFunc(nullptr, agentXMLErrorFunc);
272+
273+
doc = xmlReadMemory(deviceXml.c_str(), int32_t(deviceXml.length()), "DeviceStream.xml",
274+
nullptr, XML_PARSE_NOBLANKS);
275+
if (!doc)
276+
throw runtime_error("Failed to parse device XML");
277+
278+
auto root = xmlDocGetRootElement(doc);
279+
if (!root)
280+
throw runtime_error("Device XML has no root element");
281+
282+
xmlNodePtr deviceNode = nullptr;
283+
if (xmlStrcmp(root->name, BAD_CAST "MTConnectDevices") == 0)
272284
{
273-
LOG(warning) << "Errors parsing Device: " << deviceXml;
274-
for (auto &e : errors)
285+
for (auto child = root->children; child; child = child->next)
275286
{
276-
LOG(warning) << " " << e->what();
287+
if (xmlStrcmp(child->name, BAD_CAST "Devices") == 0)
288+
{
289+
deviceNode = child->children;
290+
break;
291+
}
277292
}
278293
}
294+
else if (xmlStrcmp(root->name, BAD_CAST "Device") == 0)
295+
{
296+
deviceNode = root;
297+
}
279298
else
280299
{
281-
device = dynamic_pointer_cast<Device>(entity);
300+
throw runtime_error("Root element of device XML must be either MTConnectDevices or Device");
282301
}
302+
303+
if (!deviceNode)
304+
throw runtime_error("No Device node found in device XML");
305+
306+
entity::ErrorList errors;
307+
auto entity = entity::XmlParser::parseXmlNode(Device::getRoot(), deviceNode, errors);
308+
309+
for (auto &e : errors)
310+
{
311+
if (entity)
312+
LOG(warning) << "When parsing device, a problem was skipped: " << e->what();
313+
else
314+
LOG(error) << "Failed to parse device: " << e->what();
315+
}
316+
317+
if (entity)
318+
device = dynamic_pointer_cast<Device>(entity);
319+
else
320+
LOG(error) << "Failed to parse device, skipping";
321+
322+
xmlFreeDoc(doc);
323+
doc = nullptr;
324+
}
325+
catch (const runtime_error &e)
326+
{
327+
if (doc)
328+
xmlFreeDoc(doc);
329+
LOG(error) << "Cannot parse device XML: " << e.what();
283330
}
284331
catch (const string &e)
285332
{
286-
LOG(fatal) << "Cannot parse XML document: " << e;
287-
throw FatalException();
333+
if (doc)
334+
xmlFreeDoc(doc);
335+
LOG(error) << "Cannot parse XML document: " << e;
336+
}
337+
catch (...)
338+
{
339+
if (doc)
340+
xmlFreeDoc(doc);
341+
LOG(error) << "Cannot parse XML document: unknown exception";
288342
}
289343

290344
return device;

‎src/mtconnect/sink/rest_sink/request.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace mtconnect::sink::rest_sink {
4545
std::string m_contentType; ///< The content type for the body
4646
std::string m_path; ///< The URI for the request
4747
std::string m_foreignIp; ///< The requestors IP Address
48+
std::string m_foreignHost; ///< The requestors IP Address
4849
uint16_t m_foreignPort; ///< The requestors Port
4950
QueryMap m_query; ///< The parsed query parameters
5051
ParameterMap m_parameters; ///< The parsed path parameters

‎src/mtconnect/sink/rest_sink/server.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ namespace mtconnect::sink::rest_sink {
121121
fail(ec, "Cannot open server socket");
122122
return;
123123
}
124+
if (m_address.is_v6())
125+
{
126+
// Enable dual-stack by default. It will allow 0.0.0.0 if ::
127+
m_acceptor.set_option(boost::asio::ip::v6_only(false), ec);
128+
ec = {}; // not fatal if unsupported
129+
}
124130
m_acceptor.set_option(boost::asio::socket_base::reuse_address(true), ec);
125131
if (ec)
126132
{

‎src/mtconnect/sink/rest_sink/server.hpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ namespace mtconnect::sink::rest_sink {
5252
/// @param options configuration options
5353
/// - Port, defaults to 5000
5454
/// - AllowPut, defaults to false
55-
/// - ServerIp, defaults to 0.0.0.0
55+
/// - ServerIp, defaults to ::
5656
/// - HttpHeaders
5757
Server(boost::asio::io_context &context, const ConfigOptions &options = {})
5858
: m_context(context),
@@ -65,7 +65,7 @@ namespace mtconnect::sink::rest_sink {
6565
auto inter = GetOption<std::string>(options, configuration::ServerIp);
6666
if (!inter)
6767
{
68-
m_address = boost::asio::ip::make_address("0.0.0.0");
68+
m_address = boost::asio::ip::make_address("::");
6969
}
7070
else
7171
{
@@ -201,6 +201,7 @@ namespace mtconnect::sink::rest_sink {
201201
RestError re(error, request->m_accepts, status::not_found, std::nullopt,
202202
request->m_requestId);
203203
re.setUri(request->getUri());
204+
LOG(warning) << "[" << request->m_foreignHost << "]: " << txt.str();
204205
m_errorFunction(session, re);
205206
}
206207
}

‎src/mtconnect/sink/rest_sink/session_impl.cpp‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,17 @@ namespace mtconnect::sink::rest_sink {
239239
}
240240

241241
m_request->m_foreignIp = remote.address().to_string();
242+
if (auto a = msg.find(http::field::forwarded); a != msg.end())
243+
m_request->m_foreignHost = string(a->value());
244+
else if (auto a = msg.find(http::field::host); a != msg.end())
245+
m_request->m_foreignHost = string(a->value());
246+
else
247+
m_request->m_foreignHost = m_request->m_foreignIp;
242248
m_request->m_foreignPort = remote.port();
243249
if (auto a = msg.find(http::field::connection); a != msg.end())
244250
m_close = a->value() == "close";
245251

246-
LOG(info) << "ReST Request: From [" << m_request->m_foreignIp << ':' << remote.port()
252+
LOG(info) << "ReST Request: From [" << m_request->m_foreignHost << ':' << remote.port()
247253
<< "]: " << msg.method() << " " << msg.target();
248254

249255
// Check if this is a websocket upgrade request. If so, begin a websocket session.
@@ -302,7 +308,7 @@ namespace mtconnect::sink::rest_sink {
302308
m_complete = complete;
303309
m_mimeType = mimeType;
304310
m_streaming = true;
305-
311+
306312
auto now = std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::now());
307313
std::string date = std::format("{:%a, %d %b %Y %T} GMT", now);
308314

‎test_package/agent_asset_test.cpp‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ TEST_F(AgentAssetTest, should_add_asset_changed_and_asset_added_with_discrete_in
643643
}
644644
}
645645

646-
TEST_F(AgentAssetTest, AssetPrependId)
646+
TEST_F(AgentAssetTest, asset_id_is_zero_padded_when_prepend_id_prefix_is_used)
647647
{
648648
addAdapter();
649649
auto agent = m_agentTestHelper->getAgent();
@@ -957,7 +957,7 @@ TEST_F(AgentAssetTest, should_respond_to_http_push_with_list_of_errors)
957957
}
958958
}
959959

960-
TEST_F(AgentAssetTest, update_asset_count_data_item_v2_0)
960+
TEST_F(AgentAssetTest, asset_count_data_set_is_updated_when_assets_are_added_or_removed)
961961
{
962962
m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 10, "2.0", 4, true);
963963
addAdapter();
@@ -1031,7 +1031,7 @@ TEST_F(AgentAssetTest, update_asset_count_data_item_v2_0)
10311031
}
10321032
}
10331033

1034-
TEST_F(AgentAssetTest, asset_count_should_not_occur_in_header_post_20)
1034+
TEST_F(AgentAssetTest, asset_count_is_absent_from_probe_header_in_schema_2_0)
10351035
{
10361036
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);
10371037

@@ -1057,7 +1057,7 @@ TEST_F(AgentAssetTest, asset_count_should_not_occur_in_header_post_20)
10571057
}
10581058
}
10591059

1060-
TEST_F(AgentAssetTest, asset_count_should_track_asset_additions_by_type)
1060+
TEST_F(AgentAssetTest, asset_count_tracks_additions_and_removals_per_type)
10611061
{
10621062
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);
10631063

@@ -1115,7 +1115,7 @@ TEST_F(AgentAssetTest, asset_count_should_track_asset_additions_by_type)
11151115
}
11161116
}
11171117

1118-
TEST_F(AgentAssetTest, asset_should_also_work_using_post_with_assets)
1118+
TEST_F(AgentAssetTest, assets_endpoint_accepts_post_requests_for_asset_storage)
11191119
{
11201120
auto agent = m_agentTestHelper->createAgent("/samples/test_config.xml", 8, 4, "2.0", 4, true);
11211121

‎test_package/agent_test.cpp‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class AgentTest : public testing::Test
8888
std::chrono::milliseconds m_delay {};
8989
};
9090

91-
TEST_F(AgentTest, Constructor)
91+
TEST_F(AgentTest, agent_throws_fatal_exception_for_bad_path_and_initializes_with_valid_path)
9292
{
9393
using namespace configuration;
9494
ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.7"s}};
@@ -109,7 +109,7 @@ TEST_F(AgentTest, Constructor)
109109
ASSERT_NO_THROW(agent->initialize(context));
110110
}
111111

112-
TEST_F(AgentTest, Probe)
112+
TEST_F(AgentTest, probe_endpoint_returns_device_name_for_multiple_paths)
113113
{
114114
{
115115
PARSE_XML_RESPONSE("/probe");
@@ -132,7 +132,7 @@ TEST_F(AgentTest, Probe)
132132
}
133133
}
134134

135-
TEST_F(AgentTest, FailWithDuplicateDeviceUUID)
135+
TEST_F(AgentTest, agent_throws_fatal_exception_when_devices_have_duplicate_uuid)
136136
{
137137
using namespace configuration;
138138
ConfigOptions options {{BufferSize, 17}, {MaxAssets, 8}, {SchemaVersion, "1.5"s}};
@@ -519,7 +519,7 @@ TEST_F(AgentTest, should_report_2_6_out_of_range_for_current_at)
519519
}
520520
}
521521

522-
TEST_F(AgentTest, AddAdapter) { addAdapter(); }
522+
TEST_F(AgentTest, adapter_can_be_added_to_agent) { addAdapter(); }
523523

524524
TEST_F(AgentTest, should_download_file)
525525
{
@@ -1271,7 +1271,7 @@ TEST_F(AgentTest, should_ignore_timestamps_if_configured_to_do_so)
12711271
}
12721272
}
12731273

1274-
TEST_F(AgentTest, InitialTimeSeriesValues)
1274+
TEST_F(AgentTest, time_series_data_item_reports_unavailable_initially)
12751275
{
12761276
addAdapter();
12771277

@@ -2401,7 +2401,7 @@ TEST_F(AgentTest, put_condition_should_parse_condition_data)
24012401
}
24022402
}
24032403

2404-
TEST_F(AgentTest, shound_add_asset_count_when_20)
2404+
TEST_F(AgentTest, asset_count_data_item_is_added_to_probe_in_schema_2_0)
24052405
{
24062406
m_agentTestHelper->createAgent("/samples/min_config.xml", 8, 4, "2.0", 25);
24072407

0 commit comments

Comments
 (0)