diff --git a/wpiutil/src/main/java/edu/wpi/first/util/MulticastServiceResolver.java b/wpiutil/src/main/java/edu/wpi/first/util/MulticastServiceResolver.java index fda3e52d2f..3e331f2515 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/MulticastServiceResolver.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/MulticastServiceResolver.java @@ -38,7 +38,7 @@ public class MulticastServiceResolver implements AutoCloseable { return WPIUtilJNI.getMulticastServiceResolverEventHandle(m_handle); } - public ServiceData getData() { + public ServiceData[] getData() { return WPIUtilJNI.getMulticastServiceResolverData(m_handle); } } diff --git a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java index 12318af01a..35a9dbdbaf 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java @@ -146,5 +146,5 @@ public final class WPIUtilJNI { public static native int getMulticastServiceResolverEventHandle(int handle); - public static native ServiceData getMulticastServiceResolverData(int handle); + public static native ServiceData[] getMulticastServiceResolverData(int handle); } diff --git a/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp b/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp index 00e2513500..015a3a2cc6 100644 --- a/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp +++ b/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp @@ -63,72 +63,90 @@ WPI_EventHandle WPI_GetMulticastServiceResolverEventHandle( return resolver->GetEventHandle(); } -WPI_ServiceData* WPI_GetMulticastServiceResolverData( - WPI_MulticastServiceResolverHandle handle) { - wpi::MulticastServiceResolver::ServiceData data; +WPI_ServiceData** WPI_GetMulticastServiceResolverData( + WPI_MulticastServiceResolverHandle handle, int32_t* dataCount) { + std::vector allData; { auto& manager = wpi::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; - data = resolver->GetData(); + allData = resolver->GetData(); } - size_t allocSize = sizeof(WPI_ServiceData); - // Include space for hostName and serviceType (+ terminators) - allocSize += data.hostName.size() + data.serviceName.size() + 2; + if (allData.empty()) { + *dataCount = 0; + return nullptr; + } + size_t allocSize = sizeof(WPI_ServiceData) * allData.size(); + allocSize += sizeof(WPI_ServiceData*) * allData.size(); - size_t keysTotalLength = 0; - size_t valuesTotalLength = 0; - // Include space for all keys and values, and pointer array - for (auto&& t : data.txt) { - allocSize += sizeof(const char*); - keysTotalLength += (t.first.size() + 1); - allocSize += sizeof(const char*); - valuesTotalLength += (t.second.size() + 1); + for (auto&& data : allData) { + // Include space for hostName and serviceType (+ terminators) + allocSize += data.hostName.size() + data.serviceName.size() + 2; + + size_t keysTotalLength = 0; + size_t valuesTotalLength = 0; + // Include space for all keys and values, and pointer array + for (auto&& t : data.txt) { + allocSize += sizeof(const char*); + keysTotalLength += (t.first.size() + 1); + allocSize += sizeof(const char*); + valuesTotalLength += (t.second.size() + 1); + } + allocSize += keysTotalLength; + allocSize += valuesTotalLength; } - allocSize += keysTotalLength; - allocSize += valuesTotalLength; + uint8_t* cDataRaw = reinterpret_cast(wpi::safe_malloc(allocSize)); if (!cDataRaw) { return nullptr; } - WPI_ServiceData* cData = reinterpret_cast(cDataRaw); - cData->ipv4Address = data.ipv4Address; - cData->port = data.port; - cData->txtCount = data.txt.size(); - cDataRaw += sizeof(WPI_ServiceData); + WPI_ServiceData** rootArray = reinterpret_cast(cDataRaw); + cDataRaw += (sizeof(WPI_ServiceData*) + allData.size()); + WPI_ServiceData** currentData = rootArray; - std::memcpy(cDataRaw, data.hostName.c_str(), data.hostName.size() + 1); - cData->hostName = reinterpret_cast(cDataRaw); - cDataRaw += data.hostName.size() + 1; + for (auto&& data : allData) { + WPI_ServiceData* cData = reinterpret_cast(cDataRaw); + *currentData = cData; + currentData++; + cData->ipv4Address = data.ipv4Address; + cData->port = data.port; + cData->txtCount = data.txt.size(); + cDataRaw += sizeof(WPI_ServiceData); - std::memcpy(cDataRaw, data.serviceName.c_str(), data.serviceName.size() + 1); - cData->serviceName = reinterpret_cast(cDataRaw); - cDataRaw += data.serviceName.size() + 1; + std::memcpy(cDataRaw, data.hostName.c_str(), data.hostName.size() + 1); + cData->hostName = reinterpret_cast(cDataRaw); + cDataRaw += data.hostName.size() + 1; - char** valuesPtrArr = reinterpret_cast(cDataRaw); - cDataRaw += (sizeof(char**) * data.txt.size()); - char** keysPtrArr = reinterpret_cast(cDataRaw); - cDataRaw += (sizeof(char**) * data.txt.size()); + std::memcpy(cDataRaw, data.serviceName.c_str(), + data.serviceName.size() + 1); + cData->serviceName = reinterpret_cast(cDataRaw); + cDataRaw += data.serviceName.size() + 1; - cData->txtKeys = const_cast(keysPtrArr); - cData->txtValues = const_cast(valuesPtrArr); + char** valuesPtrArr = reinterpret_cast(cDataRaw); + cDataRaw += (sizeof(char**) * data.txt.size()); + char** keysPtrArr = reinterpret_cast(cDataRaw); + cDataRaw += (sizeof(char**) * data.txt.size()); - for (size_t i = 0; i < data.txt.size(); i++) { - keysPtrArr[i] = reinterpret_cast(cDataRaw); - std::memcpy(keysPtrArr[i], data.txt[i].first.c_str(), - data.txt[i].first.size() + 1); - cDataRaw += (data.txt[i].first.size() + 1); + cData->txtKeys = const_cast(keysPtrArr); + cData->txtValues = const_cast(valuesPtrArr); - valuesPtrArr[i] = reinterpret_cast(cDataRaw); - std::memcpy(valuesPtrArr[i], data.txt[i].second.c_str(), - data.txt[i].second.size() + 1); - cDataRaw += (data.txt[i].second.size() + 1); + for (size_t i = 0; i < data.txt.size(); i++) { + keysPtrArr[i] = reinterpret_cast(cDataRaw); + std::memcpy(keysPtrArr[i], data.txt[i].first.c_str(), + data.txt[i].first.size() + 1); + cDataRaw += (data.txt[i].first.size() + 1); + + valuesPtrArr[i] = reinterpret_cast(cDataRaw); + std::memcpy(valuesPtrArr[i], data.txt[i].second.c_str(), + data.txt[i].second.size() + 1); + cDataRaw += (data.txt[i].second.size() + 1); + } } - return cData; + return rootArray; } -void WPI_FreeServiceData(WPI_ServiceData* serviceData) { +void WPI_FreeServiceData(WPI_ServiceData** serviceData) { std::free(serviceData); } } // extern "C" diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp index ecd8f06126..29682715c0 100644 --- a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp +++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp @@ -22,6 +22,7 @@ static uint64_t mockNow = 0; static JException interruptedEx; static JClass serviceDataCls; +static JGlobal serviceDataEmptyArray; extern "C" { @@ -41,6 +42,12 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { return JNI_ERR; } + serviceDataEmptyArray = JGlobal{ + env, env->NewObjectArray(0, serviceDataCls, nullptr)}; + if (serviceDataEmptyArray == nullptr) { + return JNI_ERR; + } + return JNI_VERSION_1_6; } @@ -49,8 +56,10 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) { if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return; } - interruptedEx.free(env); + + serviceDataEmptyArray.free(env); serviceDataCls.free(env); + interruptedEx.free(env); } /* @@ -485,9 +494,9 @@ Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverEventHandle /* * Class: edu_wpi_first_util_WPIUtilJNI * Method: getMulticastServiceResolverData - * Signature: (I)Ljava/lang/Object; + * Signature: (I)[Ljava/lang/Object; */ -JNIEXPORT jobject JNICALL +JNIEXPORT jobjectArray JNICALL Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverData (JNIEnv* env, jclass, jint handle) { @@ -496,27 +505,46 @@ Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverData "(JILjava/lang/String;Ljava/lang/String;[Ljava/lang/" "String;[Ljava/lang/String;)V"); auto& manager = wpi::GetMulticastManager(); - std::scoped_lock lock{manager.mutex}; - auto& resolver = manager.resolvers[handle]; - auto data = resolver->GetData(); - JLocal serviceName{env, MakeJString(env, data.serviceName)}; - JLocal hostName{env, MakeJString(env, data.hostName)}; - - wpi::SmallVector keysRef; - wpi::SmallVector valuesRef; - - for (auto&& txt : data.txt) { - keysRef.emplace_back(txt.first); - valuesRef.emplace_back(txt.second); + std::vector allData; + { + std::scoped_lock lock{manager.mutex}; + auto& resolver = manager.resolvers[handle]; + allData = resolver->GetData(); + } + if (allData.empty()) { + return serviceDataEmptyArray; } - JLocal keys{env, MakeJStringArray(env, keysRef)}; - JLocal values{env, MakeJStringArray(env, valuesRef)}; + JLocal returnData{ + env, env->NewObjectArray(allData.size(), serviceDataCls, nullptr)}; - return env->NewObject(serviceDataCls, constructor, - static_cast(data.ipv4Address), - static_cast(data.port), serviceName.obj(), - hostName.obj(), keys.obj(), values.obj()); + for (auto&& data : allData) { + JLocal serviceName{env, MakeJString(env, data.serviceName)}; + JLocal hostName{env, MakeJString(env, data.hostName)}; + + wpi::SmallVector keysRef; + wpi::SmallVector valuesRef; + + size_t index = 0; + for (auto&& txt : data.txt) { + keysRef.emplace_back(txt.first); + valuesRef.emplace_back(txt.second); + } + + JLocal keys{env, MakeJStringArray(env, keysRef)}; + JLocal values{env, MakeJStringArray(env, valuesRef)}; + + JLocal dataItem{ + env, env->NewObject(serviceDataCls, constructor, + static_cast(data.ipv4Address), + static_cast(data.port), serviceName.obj(), + hostName.obj(), keys.obj(), values.obj())}; + + env->SetObjectArrayElement(returnData, index, dataItem); + index++; + } + + return returnData; } } // extern "C" diff --git a/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h b/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h index ffd95475d1..1cf769816a 100644 --- a/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h +++ b/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h @@ -14,7 +14,7 @@ #include #include -#include "wpi/ConcurrentQueue.h" +#include "wpi/mutex.h" #include "wpi/span.h" namespace wpi { class MulticastServiceResolver { @@ -30,14 +30,29 @@ class MulticastServiceResolver { }; void Start(); void Stop(); - WPI_EventHandle GetEventHandle() { return event.GetHandle(); } - ServiceData GetData() { return eventQueue.pop(); } + WPI_EventHandle GetEventHandle() const { return event.GetHandle(); } + std::vector GetData() { + std::scoped_lock lock{mutex}; + event.Reset(); + if (queue.empty()) { + return {}; + } + std::vector ret; + queue.swap(ret); + return ret; + } bool HasImplementation() const; struct Impl; private: - wpi::Event event; - wpi::ConcurrentQueue eventQueue; + void PushData(ServiceData&& data) { + std::scoped_lock lock{mutex}; + queue.emplace_back(std::forward(data)); + event.Set(); + } + wpi::Event event{true}; + std::vector queue; + wpi::mutex mutex; std::unique_ptr pImpl; }; } // namespace wpi @@ -77,10 +92,10 @@ typedef struct WPI_ServiceData { // NOLINT const char** txtValues; } WPI_ServiceData; -WPI_ServiceData* WPI_GetMulticastServiceResolverData( - WPI_MulticastServiceResolverHandle handle); +WPI_ServiceData** WPI_GetMulticastServiceResolverData( + WPI_MulticastServiceResolverHandle handle, int32_t* dataCount); -void WPI_FreeServiceData(WPI_ServiceData* serviceData); +void WPI_FreeServiceData(WPI_ServiceData** serviceData); #ifdef __cplusplus } // extern "C" diff --git a/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp b/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp index eb05916fee..129fd67304 100644 --- a/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp +++ b/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp @@ -19,8 +19,7 @@ struct MulticastServiceResolver::Impl { MulticastServiceResolver* resolver; void onFound(ServiceData&& data) { - resolver->eventQueue.push(std::move(data)); - resolver->event.Set(); + resolver->PushData(std::forward(data)); } }; diff --git a/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp b/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp index f8a3cfabf9..4af8cadf91 100644 --- a/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp +++ b/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp @@ -38,8 +38,7 @@ struct MulticastServiceResolver::Impl { DNSServiceRef serviceRef = nullptr; void onFound(ServiceData&& data) { - resolver->eventQueue.push(std::move(data)); - resolver->event.Set(); + resolver->PushData(std::forward(data)); } }; diff --git a/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp b/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp index 40f9b897a4..c9452517bd 100644 --- a/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp +++ b/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp @@ -28,8 +28,7 @@ struct MulticastServiceResolver::Impl { MulticastServiceResolver* resolver; void onFound(ServiceData&& data) { - resolver->eventQueue.push(std::move(data)); - resolver->event.Set(); + resolver->PushData(std::forward(data)); } };