2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2015-07-16 22:55:50 -07:00
|
|
|
|
|
|
|
|
#include "Dispatcher.h"
|
|
|
|
|
|
2015-07-29 20:33:26 -07:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
|
2021-06-06 19:51:14 -07:00
|
|
|
#include <wpi/SmallVector.h>
|
2021-06-06 16:13:58 -07:00
|
|
|
#include <wpi/StringExtras.h>
|
2021-12-12 20:09:57 -08:00
|
|
|
#include <wpi/json_serializer.h>
|
|
|
|
|
#include <wpi/raw_ostream.h>
|
2020-12-12 21:13:16 -08:00
|
|
|
#include <wpi/timestamp.h>
|
2022-05-07 10:54:14 -07:00
|
|
|
#include <wpinet/TCPAcceptor.h>
|
|
|
|
|
#include <wpinet/TCPConnector.h>
|
2018-04-29 23:33:19 -07:00
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
#include "IConnectionNotifier.h"
|
|
|
|
|
#include "IStorage.h"
|
2017-08-19 23:08:27 -07:00
|
|
|
#include "Log.h"
|
2017-09-04 22:01:59 -07:00
|
|
|
#include "NetworkConnection.h"
|
2015-07-16 22:55:50 -07:00
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
using namespace nt;
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2021-12-12 20:09:57 -08:00
|
|
|
static std::string ConnInfoToJson(bool connected, const ConnectionInfo& info) {
|
|
|
|
|
std::string str;
|
|
|
|
|
wpi::raw_string_ostream os{str};
|
|
|
|
|
wpi::json::serializer s{os, ' ', 0};
|
|
|
|
|
os << "{\"connected\":" << (connected ? "true" : "false");
|
|
|
|
|
os << ",\"remote_id\":\"";
|
|
|
|
|
s.dump_escaped(info.remote_id, false);
|
|
|
|
|
os << "\",\"remote_ip\":\"";
|
|
|
|
|
s.dump_escaped(info.remote_ip, false);
|
|
|
|
|
os << "\",\"remote_port\":";
|
|
|
|
|
s.dump_integer(static_cast<uint64_t>(info.remote_port));
|
|
|
|
|
os << ",\"protocol_version\":";
|
|
|
|
|
s.dump_integer(static_cast<uint64_t>(info.protocol_version));
|
|
|
|
|
os << "}";
|
|
|
|
|
os.flush();
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
void Dispatcher::StartServer(std::string_view persist_filename,
|
2015-08-19 19:09:25 -07:00
|
|
|
const char* listen_address, unsigned int port) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string listen_address_copy(wpi::trim(listen_address));
|
2016-07-27 00:39:38 -07:00
|
|
|
DispatcherBase::StartServer(
|
|
|
|
|
persist_filename,
|
|
|
|
|
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
|
2018-12-29 14:47:25 -08:00
|
|
|
static_cast<int>(port), listen_address_copy.c_str(), m_logger)));
|
2015-08-02 00:33:41 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-04 16:01:42 -07:00
|
|
|
void Dispatcher::SetServer(const char* server_name, unsigned int port) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string server_name_copy(wpi::trim(server_name));
|
2016-11-04 16:01:42 -07:00
|
|
|
SetConnector([=]() -> std::unique_ptr<wpi::NetworkStream> {
|
2016-07-27 00:39:38 -07:00
|
|
|
return wpi::TCPConnector::connect(server_name_copy.c_str(),
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
static_cast<int>(port), m_logger, 1);
|
2015-08-29 00:07:10 -07:00
|
|
|
});
|
2015-08-02 00:33:41 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-04 16:01:42 -07:00
|
|
|
void Dispatcher::SetServer(
|
2021-06-06 19:51:14 -07:00
|
|
|
wpi::span<const std::pair<std::string_view, unsigned int>> servers) {
|
2018-04-29 23:33:19 -07:00
|
|
|
wpi::SmallVector<std::pair<std::string, int>, 16> servers_copy;
|
2020-12-28 12:58:06 -08:00
|
|
|
for (const auto& server : servers) {
|
2021-06-06 16:13:58 -07:00
|
|
|
servers_copy.emplace_back(std::string{wpi::trim(server.first)},
|
2017-08-13 12:05:29 -07:00
|
|
|
static_cast<int>(server.second));
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2017-08-13 12:05:29 -07:00
|
|
|
|
|
|
|
|
SetConnector([=]() -> std::unique_ptr<wpi::NetworkStream> {
|
2018-04-29 23:33:19 -07:00
|
|
|
wpi::SmallVector<std::pair<const char*, int>, 16> servers_copy2;
|
2020-12-28 12:58:06 -08:00
|
|
|
for (const auto& server : servers_copy) {
|
2017-08-13 12:05:29 -07:00
|
|
|
servers_copy2.emplace_back(server.first.c_str(), server.second);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
return wpi::TCPConnector::connect_parallel(servers_copy2, m_logger, 1);
|
2017-08-13 12:05:29 -07:00
|
|
|
});
|
2016-04-08 13:31:35 -07:00
|
|
|
}
|
|
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
void Dispatcher::SetServerTeam(unsigned int team, unsigned int port) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::pair<std::string_view, unsigned int> servers[5];
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
// 10.te.am.2
|
2021-06-06 16:13:58 -07:00
|
|
|
auto fixed = fmt::format("10.{}.{}.2", static_cast<int>(team / 100),
|
|
|
|
|
static_cast<int>(team % 100));
|
|
|
|
|
servers[0] = {fixed, port};
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
// 172.22.11.2
|
2021-06-06 16:13:58 -07:00
|
|
|
servers[1] = {"172.22.11.2", port};
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
// roboRIO-<team>-FRC.local
|
2021-06-06 16:13:58 -07:00
|
|
|
auto mdns = fmt::format("roboRIO-{}-FRC.local", team);
|
|
|
|
|
servers[2] = {mdns, port};
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
// roboRIO-<team>-FRC.lan
|
2021-06-06 16:13:58 -07:00
|
|
|
auto mdns_lan = fmt::format("roboRIO-{}-FRC.lan", team);
|
|
|
|
|
servers[3] = {mdns_lan, port};
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
// roboRIO-<team>-FRC.frc-field.local
|
2021-06-06 16:13:58 -07:00
|
|
|
auto field_local = fmt::format("roboRIO-{}-FRC.frc-field.local", team);
|
|
|
|
|
servers[4] = {field_local, port};
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
|
|
|
|
SetServer(servers);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-04 16:01:42 -07:00
|
|
|
void Dispatcher::SetServerOverride(const char* server_name, unsigned int port) {
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string server_name_copy(wpi::trim(server_name));
|
2016-11-04 16:01:42 -07:00
|
|
|
SetConnectorOverride([=]() -> std::unique_ptr<wpi::NetworkStream> {
|
|
|
|
|
return wpi::TCPConnector::connect(server_name_copy.c_str(),
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
static_cast<int>(port), m_logger, 1);
|
2016-11-04 16:01:42 -07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
void Dispatcher::ClearServerOverride() {
|
|
|
|
|
ClearConnectorOverride();
|
|
|
|
|
}
|
2016-11-04 16:01:42 -07:00
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
DispatcherBase::DispatcherBase(IStorage& storage, IConnectionNotifier& notifier,
|
|
|
|
|
wpi::Logger& logger)
|
|
|
|
|
: m_storage(storage), m_notifier(notifier), m_logger(logger) {
|
2015-07-20 20:21:37 -07:00
|
|
|
m_active = false;
|
|
|
|
|
m_update_rate = 100;
|
|
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
DispatcherBase::~DispatcherBase() {
|
|
|
|
|
Stop();
|
2021-12-12 20:09:57 -08:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock(m_user_mutex);
|
|
|
|
|
for (auto&& datalog : m_dataloggers) {
|
|
|
|
|
m_notifier.Remove(datalog.notifier);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
unsigned int DispatcherBase::GetNetworkMode() const {
|
|
|
|
|
return m_networkMode;
|
|
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
|
2019-12-29 14:56:41 -06:00
|
|
|
void DispatcherBase::StartLocal() {
|
|
|
|
|
{
|
|
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-12-29 14:56:41 -06:00
|
|
|
m_active = true;
|
|
|
|
|
}
|
|
|
|
|
m_networkMode = NT_NET_MODE_LOCAL;
|
|
|
|
|
m_storage.SetDispatcher(this, false);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 00:39:38 -07:00
|
|
|
void DispatcherBase::StartServer(
|
2021-06-06 16:13:58 -07:00
|
|
|
std::string_view persist_filename,
|
2016-07-27 00:39:38 -07:00
|
|
|
std::unique_ptr<wpi::NetworkAcceptor> acceptor) {
|
2015-07-17 22:39:36 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
m_active = true;
|
|
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_SERVER | NT_NET_MODE_STARTING;
|
2021-06-06 16:13:58 -07:00
|
|
|
m_persist_filename = persist_filename;
|
2015-08-02 00:33:41 -07:00
|
|
|
m_server_acceptor = std::move(acceptor);
|
2015-07-29 23:45:04 -07:00
|
|
|
|
2015-08-19 19:09:25 -07:00
|
|
|
// Load persistent file. Ignore errors, but pass along warnings.
|
2021-06-06 16:13:58 -07:00
|
|
|
if (!persist_filename.empty()) {
|
2015-08-19 19:09:25 -07:00
|
|
|
bool first = true;
|
|
|
|
|
m_storage.LoadPersistent(
|
2017-08-19 23:08:27 -07:00
|
|
|
persist_filename, [&](size_t line, const char* msg) {
|
2015-08-19 19:09:25 -07:00
|
|
|
if (first) {
|
|
|
|
|
first = false;
|
2021-06-06 16:13:58 -07:00
|
|
|
WARNING("When reading initial persistent values from '{}':",
|
|
|
|
|
persist_filename);
|
2015-08-19 19:09:25 -07:00
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
WARNING("{}:{}: {}", persist_filename, line, msg);
|
2015-08-19 19:09:25 -07:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
m_storage.SetDispatcher(this, true);
|
2015-07-29 23:45:04 -07:00
|
|
|
|
2015-07-16 22:55:50 -07:00
|
|
|
m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
|
2015-08-02 00:33:41 -07:00
|
|
|
m_clientserver_thread = std::thread(&Dispatcher::ServerThreadMain, this);
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2016-11-04 16:01:42 -07:00
|
|
|
void DispatcherBase::StartClient() {
|
2015-07-17 22:39:36 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_active) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
m_active = true;
|
|
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_STARTING;
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
m_storage.SetDispatcher(this, false);
|
2015-07-29 23:45:04 -07:00
|
|
|
|
2015-07-16 22:55:50 -07:00
|
|
|
m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
|
2016-04-08 13:31:35 -07:00
|
|
|
m_clientserver_thread = std::thread(&Dispatcher::ClientThreadMain, this);
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::Stop() {
|
2015-08-01 23:36:28 -07:00
|
|
|
m_active = false;
|
2015-07-17 22:39:36 -07:00
|
|
|
|
|
|
|
|
// wake up dispatch thread with a flush
|
|
|
|
|
m_flush_cv.notify_one();
|
|
|
|
|
|
|
|
|
|
// wake up client thread with a reconnect
|
2016-04-08 13:31:35 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2017-08-13 12:05:29 -07:00
|
|
|
m_client_connector = nullptr;
|
2016-04-08 13:31:35 -07:00
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
ClientReconnect();
|
|
|
|
|
|
|
|
|
|
// wake up server thread by shutting down the socket
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_server_acceptor) {
|
|
|
|
|
m_server_acceptor->shutdown();
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
|
2015-10-09 23:50:01 -07:00
|
|
|
// join threads, with timeout
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_dispatch_thread.joinable()) {
|
|
|
|
|
m_dispatch_thread.join();
|
|
|
|
|
}
|
|
|
|
|
if (m_clientserver_thread.joinable()) {
|
|
|
|
|
m_clientserver_thread.join();
|
|
|
|
|
}
|
2015-08-01 23:36:28 -07:00
|
|
|
|
2017-09-04 22:01:59 -07:00
|
|
|
std::vector<std::shared_ptr<INetworkConnection>> conns;
|
2015-08-01 23:36:28 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-08-01 23:36:28 -07:00
|
|
|
conns.swap(m_connections);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close all connections
|
|
|
|
|
conns.resize(0);
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::SetUpdateRate(double interval) {
|
2020-12-12 20:16:59 -08:00
|
|
|
// don't allow update rates faster than 5 ms or slower than 1 second
|
2020-12-28 12:58:06 -08:00
|
|
|
if (interval < 0.005) {
|
2020-12-12 20:16:59 -08:00
|
|
|
interval = 0.005;
|
2020-12-28 12:58:06 -08:00
|
|
|
} else if (interval > 1.0) {
|
2015-09-06 11:41:35 -07:00
|
|
|
interval = 1.0;
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-07-20 20:19:01 -07:00
|
|
|
m_update_rate = static_cast<unsigned int>(interval * 1000);
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
void DispatcherBase::SetIdentity(std::string_view name) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2021-06-06 16:13:58 -07:00
|
|
|
m_identity = name;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::Flush() {
|
2020-12-12 21:13:16 -08:00
|
|
|
auto now = wpi::Now();
|
2015-07-17 22:39:36 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_flush_mutex);
|
2020-12-12 20:16:59 -08:00
|
|
|
// don't allow flushes more often than every 5 ms
|
2020-12-28 12:58:06 -08:00
|
|
|
if ((now - m_last_flush) < 5000) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
m_last_flush = now;
|
|
|
|
|
m_do_flush = true;
|
|
|
|
|
}
|
|
|
|
|
m_flush_cv.notify_one();
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 10:47:05 -07:00
|
|
|
std::vector<ConnectionInfo> DispatcherBase::GetConnections() const {
|
|
|
|
|
std::vector<ConnectionInfo> conns;
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!m_active) {
|
|
|
|
|
return conns;
|
|
|
|
|
}
|
2015-08-02 10:47:05 -07:00
|
|
|
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-08-02 10:47:05 -07:00
|
|
|
for (auto& conn : m_connections) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn->state() != NetworkConnection::kActive) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
conns.emplace_back(conn->info());
|
2015-08-02 10:47:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return conns;
|
|
|
|
|
}
|
|
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
bool DispatcherBase::IsConnected() const {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!m_active) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (m_networkMode == NT_NET_MODE_LOCAL) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-04-02 17:58:07 -07:00
|
|
|
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
for (auto& conn : m_connections) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn->state() == NetworkConnection::kActive) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2015-08-28 00:13:56 -07:00
|
|
|
}
|
|
|
|
|
|
2017-09-30 23:37:02 -07:00
|
|
|
unsigned int DispatcherBase::AddListener(
|
|
|
|
|
std::function<void(const ConnectionNotification& event)> callback,
|
|
|
|
|
bool immediate_notify) const {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2017-09-30 23:37:02 -07:00
|
|
|
unsigned int uid = m_notifier.Add(callback);
|
|
|
|
|
// perform immediate notifications
|
|
|
|
|
if (immediate_notify) {
|
|
|
|
|
for (auto& conn : m_connections) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn->state() != NetworkConnection::kActive) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-09-30 23:37:02 -07:00
|
|
|
m_notifier.NotifyConnection(true, conn->info(), uid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return uid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned int DispatcherBase::AddPolledListener(unsigned int poller_uid,
|
|
|
|
|
bool immediate_notify) const {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2017-09-30 23:37:02 -07:00
|
|
|
unsigned int uid = m_notifier.AddPolled(poller_uid);
|
|
|
|
|
// perform immediate notifications
|
|
|
|
|
if (immediate_notify) {
|
|
|
|
|
for (auto& conn : m_connections) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn->state() != NetworkConnection::kActive) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-09-30 23:37:02 -07:00
|
|
|
m_notifier.NotifyConnection(true, conn->info(), uid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return uid;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-12 20:09:57 -08:00
|
|
|
unsigned int DispatcherBase::StartDataLog(wpi::log::DataLog& log,
|
|
|
|
|
std::string_view name) {
|
|
|
|
|
std::scoped_lock lock(m_user_mutex);
|
|
|
|
|
auto now = nt::Now();
|
|
|
|
|
unsigned int uid = m_dataloggers.emplace_back(log, name, now);
|
|
|
|
|
m_dataloggers[uid].notifier =
|
|
|
|
|
m_notifier.Add([this, uid](const ConnectionNotification& n) {
|
|
|
|
|
std::scoped_lock lock(m_user_mutex);
|
|
|
|
|
if (uid < m_dataloggers.size() && m_dataloggers[uid].entry) {
|
|
|
|
|
m_dataloggers[uid].entry.Append(ConnInfoToJson(n.connected, n.conn),
|
|
|
|
|
nt::Now());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
for (auto& conn : m_connections) {
|
|
|
|
|
if (conn->state() != NetworkConnection::kActive) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
m_dataloggers[uid].entry.Append(ConnInfoToJson(true, conn->info()), now);
|
|
|
|
|
}
|
|
|
|
|
return uid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DispatcherBase::StopDataLog(unsigned int logger) {
|
|
|
|
|
std::scoped_lock lock(m_user_mutex);
|
|
|
|
|
m_notifier.Remove(m_dataloggers.erase(logger).notifier);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-04 16:01:42 -07:00
|
|
|
void DispatcherBase::SetConnector(Connector connector) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2017-08-13 12:05:29 -07:00
|
|
|
m_client_connector = std::move(connector);
|
2016-11-04 16:01:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DispatcherBase::SetConnectorOverride(Connector connector) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2016-11-04 16:01:42 -07:00
|
|
|
m_client_connector_override = std::move(connector);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DispatcherBase::ClearConnectorOverride() {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2016-11-04 16:01:42 -07:00
|
|
|
m_client_connector_override = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::DispatchThreadMain() {
|
2015-07-17 22:39:36 -07:00
|
|
|
auto timeout_time = std::chrono::steady_clock::now();
|
2015-08-19 19:09:25 -07:00
|
|
|
|
|
|
|
|
static const auto save_delta_time = std::chrono::seconds(1);
|
|
|
|
|
auto next_save_time = timeout_time + save_delta_time;
|
|
|
|
|
|
2015-07-17 22:39:36 -07:00
|
|
|
int count = 0;
|
2015-08-19 19:09:25 -07:00
|
|
|
|
2015-07-17 22:39:36 -07:00
|
|
|
while (m_active) {
|
|
|
|
|
// handle loop taking too long
|
|
|
|
|
auto start = std::chrono::steady_clock::now();
|
2020-12-28 12:58:06 -08:00
|
|
|
if (start > timeout_time) {
|
|
|
|
|
timeout_time = start;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
|
|
|
|
|
// wait for periodic or when flushed
|
|
|
|
|
timeout_time += std::chrono::milliseconds(m_update_rate);
|
2017-11-13 09:51:05 -08:00
|
|
|
std::unique_lock<wpi::mutex> flush_lock(m_flush_mutex);
|
2015-12-11 21:13:41 -08:00
|
|
|
m_flush_cv.wait_until(flush_lock, timeout_time,
|
|
|
|
|
[&] { return !m_active || m_do_flush; });
|
2015-07-17 22:39:36 -07:00
|
|
|
m_do_flush = false;
|
2016-10-21 20:01:41 -07:00
|
|
|
flush_lock.unlock();
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!m_active) {
|
|
|
|
|
break; // in case we were woken up to terminate
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
|
2015-08-19 19:09:25 -07:00
|
|
|
// perform periodic persistent save
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
if ((m_networkMode & NT_NET_MODE_SERVER) != 0 &&
|
|
|
|
|
!m_persist_filename.empty() && start > next_save_time) {
|
2015-08-19 19:09:25 -07:00
|
|
|
next_save_time += save_delta_time;
|
|
|
|
|
// handle loop taking too long
|
2020-12-28 12:58:06 -08:00
|
|
|
if (start > next_save_time) {
|
|
|
|
|
next_save_time = start + save_delta_time;
|
|
|
|
|
}
|
2015-08-19 19:09:25 -07:00
|
|
|
const char* err = m_storage.SavePersistent(m_persist_filename, true);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (err) {
|
2021-06-06 16:13:58 -07:00
|
|
|
WARNING("periodic persistent save: {}", err);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-08-19 19:09:25 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 20:33:26 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock user_lock(m_user_mutex);
|
2015-07-31 23:14:26 -07:00
|
|
|
bool reconnect = false;
|
2015-11-01 22:46:51 -08:00
|
|
|
|
|
|
|
|
if (++count > 10) {
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("dispatch running {} connections", m_connections.size());
|
2015-11-01 22:46:51 -08:00
|
|
|
count = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-29 20:33:26 -07:00
|
|
|
for (auto& conn : m_connections) {
|
2015-08-13 13:12:15 -07:00
|
|
|
// post outgoing messages if connection is active
|
2015-09-08 23:15:16 -07:00
|
|
|
// only send keep-alives on client
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn->state() == NetworkConnection::kActive) {
|
2017-06-02 20:25:20 -04:00
|
|
|
conn->PostOutgoing((m_networkMode & NT_NET_MODE_CLIENT) != 0);
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
|
|
|
|
|
// if client, reconnect if connection died
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
if ((m_networkMode & NT_NET_MODE_CLIENT) != 0 &&
|
2020-12-28 12:58:06 -08:00
|
|
|
conn->state() == NetworkConnection::kDead) {
|
2015-07-31 23:14:26 -07:00
|
|
|
reconnect = true;
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-07-31 23:14:26 -07:00
|
|
|
}
|
|
|
|
|
// reconnect if we disconnected (and a reconnect is not in progress)
|
|
|
|
|
if (reconnect && !m_do_reconnect) {
|
|
|
|
|
m_do_reconnect = true;
|
|
|
|
|
m_reconnect_cv.notify_one();
|
2015-07-29 20:33:26 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 23:21:23 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::QueueOutgoing(std::shared_ptr<Message> msg,
|
2017-09-04 22:01:59 -07:00
|
|
|
INetworkConnection* only,
|
|
|
|
|
INetworkConnection* except) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock user_lock(m_user_mutex);
|
2015-07-29 23:45:04 -07:00
|
|
|
for (auto& conn : m_connections) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn.get() == except) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (only && conn.get() != only) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
auto state = conn->state();
|
2015-07-31 23:56:06 -07:00
|
|
|
if (state != NetworkConnection::kSynchronized &&
|
2020-12-28 12:58:06 -08:00
|
|
|
state != NetworkConnection::kActive) {
|
2016-11-03 21:03:45 -07:00
|
|
|
continue;
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
conn->QueueOutgoing(msg);
|
2015-07-17 22:39:36 -07:00
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::ServerThreadMain() {
|
2015-07-17 22:39:36 -07:00
|
|
|
if (m_server_acceptor->start() != 0) {
|
2015-07-16 22:55:50 -07:00
|
|
|
m_active = false;
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_SERVER | NT_NET_MODE_FAILURE;
|
2015-12-22 08:23:44 -08:00
|
|
|
return;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_SERVER;
|
2015-07-16 22:55:50 -07:00
|
|
|
while (m_active) {
|
2015-07-17 22:39:36 -07:00
|
|
|
auto stream = m_server_acceptor->accept();
|
2015-07-16 22:55:50 -07:00
|
|
|
if (!stream) {
|
|
|
|
|
m_active = false;
|
2015-12-22 08:23:44 -08:00
|
|
|
return;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
if (!m_active) {
|
|
|
|
|
m_networkMode = NT_NET_MODE_NONE;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("server: client connection from {} port {}", stream->getPeerIP(),
|
|
|
|
|
stream->getPeerPort());
|
2015-07-17 22:39:36 -07:00
|
|
|
|
2015-07-16 22:55:50 -07:00
|
|
|
// add to connections list
|
2015-07-29 23:45:04 -07:00
|
|
|
using namespace std::placeholders;
|
2015-08-13 13:12:15 -07:00
|
|
|
auto conn = std::make_shared<NetworkConnection>(
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
++m_connections_uid, std::move(stream), m_notifier, m_logger,
|
2021-01-01 10:27:49 -08:00
|
|
|
std::bind(&Dispatcher::ServerHandshake, this, _1, _2, _3), // NOLINT
|
|
|
|
|
std::bind(&IStorage::GetMessageEntryType, &m_storage, _1)); // NOLINT
|
2015-08-13 13:12:15 -07:00
|
|
|
conn->set_process_incoming(
|
2021-01-01 10:27:49 -08:00
|
|
|
std::bind(&IStorage::ProcessIncoming, &m_storage, _1, _2, // NOLINT
|
2015-08-13 13:12:15 -07:00
|
|
|
std::weak_ptr<NetworkConnection>(conn)));
|
2015-07-29 23:45:04 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-11-01 22:47:15 -08:00
|
|
|
// reuse dead connection slots
|
|
|
|
|
bool placed = false;
|
|
|
|
|
for (auto& c : m_connections) {
|
|
|
|
|
if (c->state() == NetworkConnection::kDead) {
|
|
|
|
|
c = conn;
|
|
|
|
|
placed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!placed) {
|
|
|
|
|
m_connections.emplace_back(conn);
|
|
|
|
|
}
|
2015-08-13 13:12:15 -07:00
|
|
|
conn->Start();
|
2015-07-29 23:45:04 -07:00
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_NONE;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-08 13:31:35 -07:00
|
|
|
void DispatcherBase::ClientThreadMain() {
|
2015-07-16 22:55:50 -07:00
|
|
|
while (m_active) {
|
2015-07-17 22:39:36 -07:00
|
|
|
// sleep between retries
|
2016-04-08 13:31:35 -07:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
|
|
|
|
Connector connect;
|
|
|
|
|
|
|
|
|
|
// get next server to connect to
|
|
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2016-11-04 16:01:42 -07:00
|
|
|
if (m_client_connector_override) {
|
|
|
|
|
connect = m_client_connector_override;
|
|
|
|
|
} else {
|
2017-08-13 12:05:29 -07:00
|
|
|
if (!m_client_connector) {
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_FAILURE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-08-13 12:05:29 -07:00
|
|
|
connect = m_client_connector;
|
2016-11-04 16:01:42 -07:00
|
|
|
}
|
2016-04-08 13:31:35 -07:00
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
|
2015-07-16 22:55:50 -07:00
|
|
|
// try to connect (with timeout)
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "client trying to connect");
|
2015-08-02 00:33:41 -07:00
|
|
|
auto stream = connect();
|
2017-06-02 20:25:20 -04:00
|
|
|
if (!stream) {
|
|
|
|
|
m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_FAILURE;
|
|
|
|
|
continue; // keep retrying
|
|
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "client connected");
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_CLIENT;
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2019-07-07 19:17:14 -07:00
|
|
|
std::unique_lock lock(m_user_mutex);
|
2015-07-31 20:32:52 -07:00
|
|
|
using namespace std::placeholders;
|
2015-08-13 13:12:15 -07:00
|
|
|
auto conn = std::make_shared<NetworkConnection>(
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
++m_connections_uid, std::move(stream), m_notifier, m_logger,
|
2021-01-01 10:27:49 -08:00
|
|
|
std::bind(&Dispatcher::ClientHandshake, this, _1, _2, _3), // NOLINT
|
|
|
|
|
std::bind(&IStorage::GetMessageEntryType, &m_storage, _1)); // NOLINT
|
2015-08-13 13:12:15 -07:00
|
|
|
conn->set_process_incoming(
|
2021-01-01 10:27:49 -08:00
|
|
|
std::bind(&IStorage::ProcessIncoming, &m_storage, _1, _2, // NOLINT
|
2015-08-13 13:12:15 -07:00
|
|
|
std::weak_ptr<NetworkConnection>(conn)));
|
2015-07-31 23:14:26 -07:00
|
|
|
m_connections.resize(0); // disconnect any current
|
2015-08-13 13:12:15 -07:00
|
|
|
m_connections.emplace_back(conn);
|
2015-07-31 23:14:26 -07:00
|
|
|
conn->set_proto_rev(m_reconnect_proto_rev);
|
2015-07-29 20:33:26 -07:00
|
|
|
conn->Start();
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2016-10-25 21:44:47 -07:00
|
|
|
// reconnect the next time starting with latest protocol revision
|
|
|
|
|
m_reconnect_proto_rev = 0x0300;
|
|
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// block until told to reconnect
|
|
|
|
|
m_do_reconnect = false;
|
2015-08-01 23:36:28 -07:00
|
|
|
m_reconnect_cv.wait(lock, [&] { return !m_active || m_do_reconnect; });
|
2015-07-31 20:32:52 -07:00
|
|
|
}
|
2017-06-02 20:25:20 -04:00
|
|
|
m_networkMode = NT_NET_MODE_NONE;
|
2015-07-31 20:32:52 -07:00
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
bool DispatcherBase::ClientHandshake(
|
2016-11-03 21:03:45 -07:00
|
|
|
NetworkConnection& conn, std::function<std::shared_ptr<Message>()> get_msg,
|
2021-06-06 19:51:14 -07:00
|
|
|
std::function<void(wpi::span<std::shared_ptr<Message>>)> send_msgs) {
|
2015-07-31 20:32:52 -07:00
|
|
|
// get identity
|
|
|
|
|
std::string self_id;
|
|
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-07-31 20:32:52 -07:00
|
|
|
self_id = m_identity;
|
|
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// send client hello
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "client: sending hello");
|
2021-06-06 19:51:14 -07:00
|
|
|
auto msg = Message::ClientHello(self_id);
|
|
|
|
|
send_msgs(wpi::span(&msg, 1));
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// wait for response
|
2021-06-06 19:51:14 -07:00
|
|
|
msg = get_msg();
|
2015-07-31 20:32:52 -07:00
|
|
|
if (!msg) {
|
|
|
|
|
// disconnected, retry
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "client: server disconnected before first response");
|
2015-07-31 20:32:52 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
if (msg->Is(Message::kProtoUnsup)) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if (msg->id() == 0x0200) {
|
|
|
|
|
ClientReconnect(0x0200);
|
|
|
|
|
}
|
2015-07-31 20:32:52 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool new_server = true;
|
|
|
|
|
if (conn.proto_rev() >= 0x0300) {
|
|
|
|
|
// should be server hello; if not, disconnect.
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!msg->Is(Message::kServerHello)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-07-31 20:32:52 -07:00
|
|
|
conn.set_remote_id(msg->str());
|
2020-12-28 12:58:06 -08:00
|
|
|
if ((msg->flags() & 1) != 0) {
|
|
|
|
|
new_server = false;
|
|
|
|
|
}
|
2015-07-31 20:32:52 -07:00
|
|
|
// get the next message
|
|
|
|
|
msg = get_msg();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// receive initial assignments
|
|
|
|
|
std::vector<std::shared_ptr<Message>> incoming;
|
|
|
|
|
for (;;) {
|
|
|
|
|
if (!msg) {
|
|
|
|
|
// disconnected, retry
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "client: server disconnected during initial entries");
|
2015-07-31 20:32:52 -07:00
|
|
|
return false;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG4("received init str={} id={} seq_num={}", msg->str(), msg->id(),
|
|
|
|
|
msg->seq_num_uid());
|
2020-12-28 12:58:06 -08:00
|
|
|
if (msg->Is(Message::kServerHelloDone)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-19 22:47:33 -07:00
|
|
|
// shouldn't receive a keep alive, but handle gracefully
|
|
|
|
|
if (msg->Is(Message::kKeepAlive)) {
|
|
|
|
|
msg = get_msg();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-07-31 20:32:52 -07:00
|
|
|
if (!msg->Is(Message::kEntryAssign)) {
|
|
|
|
|
// unexpected message
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0(
|
|
|
|
|
"client: received message ({}) other than entry assignment during "
|
|
|
|
|
"initial handshake",
|
|
|
|
|
msg->type());
|
2015-07-31 20:32:52 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
incoming.emplace_back(std::move(msg));
|
|
|
|
|
// get the next message
|
|
|
|
|
msg = get_msg();
|
|
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// generate outgoing assignments
|
|
|
|
|
NetworkConnection::Outgoing outgoing;
|
2015-07-18 01:29:24 -07:00
|
|
|
|
2015-08-01 11:15:04 -07:00
|
|
|
m_storage.ApplyInitialAssignments(conn, incoming, new_server, &outgoing);
|
2015-07-18 01:29:24 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (conn.proto_rev() >= 0x0300) {
|
2015-07-31 20:32:52 -07:00
|
|
|
outgoing.emplace_back(Message::ClientHelloDone());
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-07-18 01:29:24 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (!outgoing.empty()) {
|
|
|
|
|
send_msgs(outgoing);
|
|
|
|
|
}
|
2015-07-16 22:55:50 -07:00
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
INFO("client: CONNECTED to server {} port {}", conn.stream().getPeerIP(),
|
|
|
|
|
conn.stream().getPeerPort());
|
2015-07-31 20:32:52 -07:00
|
|
|
return true;
|
2015-07-17 22:39:36 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
bool DispatcherBase::ServerHandshake(
|
2016-11-03 21:03:45 -07:00
|
|
|
NetworkConnection& conn, std::function<std::shared_ptr<Message>()> get_msg,
|
2021-06-06 19:51:14 -07:00
|
|
|
std::function<void(wpi::span<std::shared_ptr<Message>>)> send_msgs) {
|
2015-07-29 20:33:26 -07:00
|
|
|
// Wait for the client to send us a hello.
|
|
|
|
|
auto msg = get_msg();
|
|
|
|
|
if (!msg) {
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "server: client disconnected before sending hello");
|
2015-07-29 20:33:26 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!msg->Is(Message::kClientHello)) {
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "server: client initial message was not client hello");
|
2015-07-29 20:33:26 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that the client requested version is not too high.
|
|
|
|
|
unsigned int proto_rev = msg->id();
|
|
|
|
|
if (proto_rev > 0x0300) {
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "server: client requested proto > 0x0300");
|
2021-06-06 19:51:14 -07:00
|
|
|
auto toSend = Message::ProtoUnsup();
|
|
|
|
|
send_msgs(wpi::span(&toSend, 1));
|
2015-07-29 20:33:26 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (proto_rev >= 0x0300) {
|
|
|
|
|
conn.set_remote_id(msg->str());
|
|
|
|
|
}
|
2015-07-29 20:33:26 -07:00
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// Set the proto version to the client requested version
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("server: client protocol {}", proto_rev);
|
2015-07-29 20:33:26 -07:00
|
|
|
conn.set_proto_rev(proto_rev);
|
2015-07-31 20:32:52 -07:00
|
|
|
|
|
|
|
|
// Send initial set of assignments
|
2015-07-29 20:33:26 -07:00
|
|
|
NetworkConnection::Outgoing outgoing;
|
|
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// Start with server hello. TODO: initial connection flag
|
2015-07-29 20:33:26 -07:00
|
|
|
if (proto_rev >= 0x0300) {
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-07-31 20:32:52 -07:00
|
|
|
outgoing.emplace_back(Message::ServerHello(0u, m_identity));
|
2015-07-29 20:33:26 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-31 20:32:52 -07:00
|
|
|
// Get snapshot of initial assignments
|
2015-08-01 11:15:04 -07:00
|
|
|
m_storage.GetInitialAssignments(conn, &outgoing);
|
2015-07-31 20:32:52 -07:00
|
|
|
|
|
|
|
|
// Finish with server hello done
|
|
|
|
|
outgoing.emplace_back(Message::ServerHelloDone());
|
|
|
|
|
|
|
|
|
|
// Batch transmit
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "server: sending initial assignments");
|
2015-07-31 20:32:52 -07:00
|
|
|
send_msgs(outgoing);
|
|
|
|
|
|
2015-07-29 20:33:26 -07:00
|
|
|
// In proto rev 3.0 and later, the handshake concludes with a client hello
|
|
|
|
|
// done message, so we can batch the assigns before marking the connection
|
|
|
|
|
// active. In pre-3.0, we need to just immediately mark it active and hand
|
|
|
|
|
// off control to the dispatcher to assign them as they arrive.
|
|
|
|
|
if (proto_rev >= 0x0300) {
|
|
|
|
|
// receive client initial assignments
|
|
|
|
|
std::vector<std::shared_ptr<Message>> incoming;
|
2015-07-31 20:32:52 -07:00
|
|
|
msg = get_msg();
|
2015-07-29 20:33:26 -07:00
|
|
|
for (;;) {
|
|
|
|
|
if (!msg) {
|
|
|
|
|
// disconnected, retry
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0("{}", "server: disconnected waiting for initial entries");
|
2015-07-29 20:33:26 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
2020-12-28 12:58:06 -08:00
|
|
|
if (msg->Is(Message::kClientHelloDone)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-19 22:47:33 -07:00
|
|
|
// shouldn't receive a keep alive, but handle gracefully
|
|
|
|
|
if (msg->Is(Message::kKeepAlive)) {
|
|
|
|
|
msg = get_msg();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-07-29 20:33:26 -07:00
|
|
|
if (!msg->Is(Message::kEntryAssign)) {
|
|
|
|
|
// unexpected message
|
2021-06-06 16:13:58 -07:00
|
|
|
DEBUG0(
|
|
|
|
|
"server: received message ({}) other than entry assignment during "
|
|
|
|
|
"initial handshake",
|
|
|
|
|
msg->type());
|
2015-07-29 20:33:26 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
incoming.push_back(msg);
|
|
|
|
|
// get the next message (blocks)
|
|
|
|
|
msg = get_msg();
|
|
|
|
|
}
|
2020-12-28 12:58:06 -08:00
|
|
|
for (auto& msg : incoming) {
|
2015-08-13 13:12:15 -07:00
|
|
|
m_storage.ProcessIncoming(msg, &conn, std::weak_ptr<NetworkConnection>());
|
2020-12-28 12:58:06 -08:00
|
|
|
}
|
2015-07-29 20:33:26 -07:00
|
|
|
}
|
2015-07-31 20:32:52 -07:00
|
|
|
|
2021-06-06 16:13:58 -07:00
|
|
|
INFO("server: client CONNECTED: {} port {}", conn.stream().getPeerIP(),
|
|
|
|
|
conn.stream().getPeerPort());
|
2015-07-29 20:33:26 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 00:33:41 -07:00
|
|
|
void DispatcherBase::ClientReconnect(unsigned int proto_rev) {
|
2020-12-28 12:58:06 -08:00
|
|
|
if ((m_networkMode & NT_NET_MODE_SERVER) != 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
{
|
2019-07-08 22:58:39 -07:00
|
|
|
std::scoped_lock lock(m_user_mutex);
|
2015-07-31 20:32:52 -07:00
|
|
|
m_reconnect_proto_rev = proto_rev;
|
2015-07-17 22:39:36 -07:00
|
|
|
m_do_reconnect = true;
|
2015-07-16 22:55:50 -07:00
|
|
|
}
|
2015-07-17 22:39:36 -07:00
|
|
|
m_reconnect_cv.notify_one();
|
|
|
|
|
}
|