diff --git a/include/ntcore_c.h b/include/ntcore_c.h index 0744e4a609..3ea3b74b68 100644 --- a/include/ntcore_c.h +++ b/include/ntcore_c.h @@ -57,6 +57,15 @@ enum NT_NotifyKind { NT_NOTIFY_FLAGS = 0x20 /* flags changed */ }; +/** Client/server modes */ +enum NT_NetworkMode { + NT_NET_MODE_NONE = 0x00, /* not running */ + NT_NET_MODE_SERVER = 0x01, /* running in server mode */ + NT_NET_MODE_CLIENT = 0x02, /* running in client mode */ + NT_NET_MODE_STARTING = 0x04, /* flag for starting (either client or server) */ + NT_NET_MODE_FAILURE = 0x08, /* flag for failure (either client or server) */ +}; + /* * Structures */ @@ -345,6 +354,11 @@ struct NT_Value** NT_UnpackRpcValues(const char* packed, size_t packed_len, */ void NT_SetNetworkIdentity(const char* name, size_t name_len); +/** + * Get the current network mode. + */ +unsigned int NT_GetNetworkMode(); + /** Start Server * Starts a server using the specified filename, listening address, and port. * diff --git a/include/ntcore_cpp.h b/include/ntcore_cpp.h index 67928f7eb8..0d484e6278 100644 --- a/include/ntcore_cpp.h +++ b/include/ntcore_cpp.h @@ -252,6 +252,7 @@ std::vector> UnpackRpcValues(StringRef packed, * Client/Server Functions */ void SetNetworkIdentity(StringRef name); +unsigned int GetNetworkMode(); void StartServer(StringRef persist_filename, const char* listen_address, unsigned int port); void StopServer(); diff --git a/java/lib/NetworkTablesJNI.cpp b/java/lib/NetworkTablesJNI.cpp index 62d37f1ac5..3ec7f65c4a 100644 --- a/java/lib/NetworkTablesJNI.cpp +++ b/java/lib/NetworkTablesJNI.cpp @@ -1502,6 +1502,17 @@ JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI nt::StopClient(); } +/* + * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI + * Method: getNetworkMode + * Signature: () + */ +JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getNetworkMode + (JNIEnv *, jclass) +{ + return nt::GetNetworkMode(); +} + /* * Class: edu_wpi_first_wpilibj_networktables_NetworkTablesJNI * Method: setServer diff --git a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java index 0271d511ac..516332fec4 100644 --- a/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java +++ b/java/src/edu/wpi/first/wpilibj/networktables/NetworkTablesJNI.java @@ -67,6 +67,12 @@ public class NetworkTablesJNI { } } + public static final int NT_NET_MODE_NONE = 0x00; + public static final int NT_NET_MODE_SERVER = 0x01; + public static final int NT_NET_MODE_CLIENT = 0x02; + public static final int NT_NET_MODE_STARTING = 0x04; + public static final int NT_NET_MODE_FAILURE = 0x08; + public static native boolean containsKey(String key); public static native int getType(String key); @@ -148,6 +154,7 @@ public class NetworkTablesJNI { // public static native byte[] getRpcResultNonblocking(int callUid) throws RpcNoResponseException; public static native void setNetworkIdentity(String name); + public static native int getNetworkMode(); public static native void startServer(String persistFilename, String listenAddress, int port); public static native void stopServer(); public static native void startClient(); diff --git a/ntcore-jni.def b/ntcore-jni.def index 14860645b1..b948984a08 100644 --- a/ntcore-jni.def +++ b/ntcore-jni.def @@ -119,6 +119,8 @@ NT_StartDSClient @119 NT_StopDSClient @120 NT_StartClientNone @121 +NT_GetNetworkMode @122 + ; JNI functions JNI_OnLoad JNI_OnUnload @@ -194,3 +196,4 @@ Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultRaw Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultBooleanArray Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultDoubleArray Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_setDefaultStringArray +Java_edu_wpi_first_wpilibj_networktables_NetworkTablesJNI_getNetworkMode diff --git a/ntcore.def b/ntcore.def index 73157c3108..0462af5097 100644 --- a/ntcore.def +++ b/ntcore.def @@ -118,3 +118,5 @@ NT_SetServerMulti @118 NT_StartDSClient @119 NT_StopDSClient @120 NT_StartClientNone @121 + +NT_GetNetworkMode @122 diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index c65514be53..979aa8594b 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -75,6 +75,10 @@ DispatcherBase::~DispatcherBase() { Stop(); } +unsigned int DispatcherBase::GetNetworkMode() const { + return m_networkMode; +} + void DispatcherBase::StartServer( StringRef persist_filename, std::unique_ptr acceptor) { @@ -83,7 +87,7 @@ void DispatcherBase::StartServer( if (m_active) return; m_active = true; } - m_server = true; + m_networkMode = NT_NET_MODE_SERVER | NT_NET_MODE_STARTING; m_persist_filename = persist_filename; m_server_acceptor = std::move(acceptor); @@ -103,7 +107,7 @@ void DispatcherBase::StartServer( using namespace std::placeholders; m_storage.SetOutgoing(std::bind(&Dispatcher::QueueOutgoing, this, _1, _2, _3), - m_server); + (m_networkMode & NT_NET_MODE_SERVER) != 0); m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this); m_clientserver_thread = std::thread(&Dispatcher::ServerThreadMain, this); @@ -115,10 +119,10 @@ void DispatcherBase::StartClient() { if (m_active) return; m_active = true; } - m_server = false; + m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_STARTING; using namespace std::placeholders; m_storage.SetOutgoing(std::bind(&Dispatcher::QueueOutgoing, this, _1, _2, _3), - m_server); + (m_networkMode & NT_NET_MODE_SERVER) != 0); m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this); m_clientserver_thread = std::thread(&Dispatcher::ClientThreadMain, this); @@ -243,7 +247,7 @@ void DispatcherBase::DispatchThreadMain() { if (!m_active) break; // in case we were woken up to terminate // perform periodic persistent save - if (m_server && !m_persist_filename.empty() && start > next_save_time) { + if ((m_networkMode & NT_NET_MODE_SERVER) != 0 && !m_persist_filename.empty() && start > next_save_time) { next_save_time += save_delta_time; // handle loop taking too long if (start > next_save_time) next_save_time = start + save_delta_time; @@ -264,10 +268,10 @@ void DispatcherBase::DispatchThreadMain() { // post outgoing messages if connection is active // only send keep-alives on client if (conn->state() == NetworkConnection::kActive) - conn->PostOutgoing(!m_server); + conn->PostOutgoing((m_networkMode & NT_NET_MODE_CLIENT) != 0); // if client, reconnect if connection died - if (!m_server && conn->state() == NetworkConnection::kDead) + if ((m_networkMode & NT_NET_MODE_CLIENT) != 0 && conn->state() == NetworkConnection::kDead) reconnect = true; } // reconnect if we disconnected (and a reconnect is not in progress) @@ -297,15 +301,20 @@ void DispatcherBase::QueueOutgoing(std::shared_ptr msg, void DispatcherBase::ServerThreadMain() { if (m_server_acceptor->start() != 0) { m_active = false; + m_networkMode = NT_NET_MODE_SERVER | NT_NET_MODE_FAILURE; return; } + m_networkMode = NT_NET_MODE_SERVER; while (m_active) { auto stream = m_server_acceptor->accept(); if (!stream) { m_active = false; return; } - if (!m_active) return; + if (!m_active) { + m_networkMode = NT_NET_MODE_NONE; + return; + } DEBUG("server: client connection from " << stream->getPeerIP() << " port " << stream->getPeerPort()); @@ -333,6 +342,7 @@ void DispatcherBase::ServerThreadMain() { conn->Start(); } } + m_networkMode = NT_NET_MODE_NONE; } void DispatcherBase::ClientThreadMain() { @@ -348,7 +358,10 @@ void DispatcherBase::ClientThreadMain() { if (m_client_connector_override) { connect = m_client_connector_override; } else { - if (m_client_connectors.empty()) continue; + if (m_client_connectors.empty()) { + m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_FAILURE; + continue; + } if (i >= m_client_connectors.size()) i = 0; connect = m_client_connectors[i++]; } @@ -357,8 +370,12 @@ void DispatcherBase::ClientThreadMain() { // try to connect (with timeout) DEBUG("client trying to connect"); auto stream = connect(); - if (!stream) continue; // keep retrying + if (!stream) { + m_networkMode = NT_NET_MODE_CLIENT | NT_NET_MODE_FAILURE; + continue; // keep retrying + } DEBUG("client connected"); + m_networkMode = NT_NET_MODE_CLIENT; std::unique_lock lock(m_user_mutex); using namespace std::placeholders; @@ -381,6 +398,7 @@ void DispatcherBase::ClientThreadMain() { m_do_reconnect = false; m_reconnect_cv.wait(lock, [&] { return !m_active || m_do_reconnect; }); } + m_networkMode = NT_NET_MODE_NONE; } bool DispatcherBase::ClientHandshake( @@ -551,7 +569,7 @@ bool DispatcherBase::ServerHandshake( } void DispatcherBase::ClientReconnect(unsigned int proto_rev) { - if (m_server) return; + if ((m_networkMode & NT_NET_MODE_SERVER) != 0) return; { std::lock_guard lock(m_user_mutex); m_reconnect_proto_rev = proto_rev; diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 2bfa228bb6..bda9561eb3 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -39,6 +39,7 @@ class DispatcherBase { virtual ~DispatcherBase(); + unsigned int GetNetworkMode() const; void StartServer(llvm::StringRef persist_filename, std::unique_ptr acceptor); void StartClient(); @@ -84,7 +85,7 @@ class DispatcherBase { Storage& m_storage; Notifier& m_notifier; - bool m_server = false; + unsigned int m_networkMode = NT_NET_MODE_NONE; std::string m_persist_filename; std::thread m_dispatch_thread; std::thread m_clientserver_thread; diff --git a/src/ntcore_c.cpp b/src/ntcore_c.cpp index 34ffb301bd..06216b1a9b 100644 --- a/src/ntcore_c.cpp +++ b/src/ntcore_c.cpp @@ -365,6 +365,10 @@ void NT_SetNetworkIdentity(const char* name, size_t name_len) { nt::SetNetworkIdentity(StringRef(name, name_len)); } +unsigned int NT_GetNetworkMode() { + return nt::GetNetworkMode(); +} + void NT_StartServer(const char* persist_filename, const char* listen_address, unsigned int port) { nt::StartServer(persist_filename, listen_address, port); diff --git a/src/ntcore_cpp.cpp b/src/ntcore_cpp.cpp index 5ae962b4be..41dfbc5171 100644 --- a/src/ntcore_cpp.cpp +++ b/src/ntcore_cpp.cpp @@ -240,6 +240,11 @@ void SetNetworkIdentity(StringRef name) { Dispatcher::GetInstance().SetIdentity(name); } +unsigned int GetNetworkMode() { + auto& d = Dispatcher::GetInstance(); + return d.GetNetworkMode(); +} + void StartServer(StringRef persist_filename, const char* listen_address, unsigned int port) { Dispatcher::GetInstance().StartServer(persist_filename, listen_address, port);