// 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. #include #include #include #include #include #include "../MulticastHandleManager.hpp" #include "org_wpilib_net_WPINetJNI.h" #include "wpi/net/MulticastServiceAnnouncer.h" #include "wpi/net/MulticastServiceResolver.h" #include "wpi/net/PortForwarder.hpp" #include "wpi/net/WebServer.hpp" #include "wpi/util/jni_util.hpp" using namespace wpi::util::java; static JClass serviceDataCls; static JGlobal serviceDataEmptyArray; extern "C" { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } serviceDataCls = JClass{env, "org/wpilib/net/ServiceData"}; if (!serviceDataCls) { return JNI_ERR; } serviceDataEmptyArray = JGlobal{ env, env->NewObjectArray(0, serviceDataCls, nullptr)}; if (serviceDataEmptyArray == nullptr) { return JNI_ERR; } return JNI_VERSION_1_6; } JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return; } serviceDataEmptyArray.free(env); serviceDataCls.free(env); } /* * Class: org_wpilib_net_WPINetJNI * Method: addPortForwarder * Signature: (ILjava/lang/String;I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_addPortForwarder (JNIEnv* env, jclass, jint port, jstring remoteHost, jint remotePort) { wpi::net::PortForwarder::GetInstance().Add(static_cast(port), JStringRef{env, remoteHost}.str(), static_cast(remotePort)); } /* * Class: org_wpilib_net_WPINetJNI * Method: removePortForwarder * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_removePortForwarder (JNIEnv* env, jclass, jint port) { wpi::net::PortForwarder::GetInstance().Remove(port); } /* * Class: org_wpilib_net_WPINetJNI * Method: startWebServer * Signature: (ILjava/lang/String;)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_startWebServer (JNIEnv* env, jclass, jint port, jstring path) { wpi::net::WebServer::GetInstance().Start(static_cast(port), JStringRef{env, path}.str()); } /* * Class: org_wpilib_net_WPINetJNI * Method: stopWebServer * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_stopWebServer (JNIEnv* env, jclass, jint port) { wpi::net::WebServer::GetInstance().Stop(port); } /* * Class: org_wpilib_net_WPINetJNI * Method: createMulticastServiceAnnouncer * Signature: (Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/Object;[Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_org_wpilib_net_WPINetJNI_createMulticastServiceAnnouncer (JNIEnv* env, jclass, jstring serviceName, jstring serviceType, jint port, jobjectArray keys, jobjectArray values) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; JStringRef serviceNameRef{env, serviceName}; JStringRef serviceTypeRef{env, serviceType}; wpi::util::SmallVector, 8> txtVec; if (keys != nullptr && values != nullptr) { size_t keysLen = env->GetArrayLength(keys); txtVec.reserve(keysLen); for (size_t i = 0; i < keysLen; i++) { JLocal key{ env, static_cast(env->GetObjectArrayElement(keys, i))}; JLocal value{ env, static_cast(env->GetObjectArrayElement(values, i))}; txtVec.emplace_back(std::pair{ JStringRef{env, key}.str(), JStringRef{env, value}.str()}); } } auto announcer = std::make_unique( serviceNameRef.str(), serviceTypeRef.str(), port, txtVec); size_t index = manager.handleIds.emplace_back(1); manager.announcers[index] = std::move(announcer); return static_cast(index); } /* * Class: org_wpilib_net_WPINetJNI * Method: freeMulticastServiceAnnouncer * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_freeMulticastServiceAnnouncer (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; manager.announcers[handle] = nullptr; manager.handleIds.erase(handle); } /* * Class: org_wpilib_net_WPINetJNI * Method: startMulticastServiceAnnouncer * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_startMulticastServiceAnnouncer (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& announcer = manager.announcers[handle]; announcer->Start(); } /* * Class: org_wpilib_net_WPINetJNI * Method: stopMulticastServiceAnnouncer * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_stopMulticastServiceAnnouncer (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& announcer = manager.announcers[handle]; announcer->Stop(); } /* * Class: org_wpilib_net_WPINetJNI * Method: getMulticastServiceAnnouncerHasImplementation * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_wpilib_net_WPINetJNI_getMulticastServiceAnnouncerHasImplementation (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& announcer = manager.announcers[handle]; return announcer->HasImplementation(); } /* * Class: org_wpilib_net_WPINetJNI * Method: createMulticastServiceResolver * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_org_wpilib_net_WPINetJNI_createMulticastServiceResolver (JNIEnv* env, jclass, jstring serviceType) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; JStringRef serviceTypeRef{env, serviceType}; auto resolver = std::make_unique(serviceTypeRef.str()); size_t index = manager.handleIds.emplace_back(2); manager.resolvers[index] = std::move(resolver); return static_cast(index); } /* * Class: org_wpilib_net_WPINetJNI * Method: freeMulticastServiceResolver * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_freeMulticastServiceResolver (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; manager.resolvers[handle] = nullptr; manager.handleIds.erase(handle); } /* * Class: org_wpilib_net_WPINetJNI * Method: startMulticastServiceResolver * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_startMulticastServiceResolver (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; resolver->Start(); } /* * Class: org_wpilib_net_WPINetJNI * Method: stopMulticastServiceResolver * Signature: (I)V */ JNIEXPORT void JNICALL Java_org_wpilib_net_WPINetJNI_stopMulticastServiceResolver (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; resolver->Stop(); } /* * Class: org_wpilib_net_WPINetJNI * Method: getMulticastServiceResolverHasImplementation * Signature: (I)Z */ JNIEXPORT jboolean JNICALL Java_org_wpilib_net_WPINetJNI_getMulticastServiceResolverHasImplementation (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; return resolver->HasImplementation(); } /* * Class: org_wpilib_net_WPINetJNI * Method: getMulticastServiceResolverEventHandle * Signature: (I)I */ JNIEXPORT jint JNICALL Java_org_wpilib_net_WPINetJNI_getMulticastServiceResolverEventHandle (JNIEnv* env, jclass, jint handle) { auto& manager = wpi::net::GetMulticastManager(); std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; return resolver->GetEventHandle(); } /* * Class: org_wpilib_net_WPINetJNI * Method: getMulticastServiceResolverData * Signature: (I)[Ljava/lang/Object; */ JNIEXPORT jobjectArray JNICALL Java_org_wpilib_net_WPINetJNI_getMulticastServiceResolverData (JNIEnv* env, jclass, jint handle) { static jmethodID constructor = env->GetMethodID(serviceDataCls, "", "(JILjava/lang/String;Ljava/lang/String;[Ljava/lang/" "String;[Ljava/lang/String;)V"); auto& manager = wpi::net::GetMulticastManager(); std::vector allData; { std::scoped_lock lock{manager.mutex}; auto& resolver = manager.resolvers[handle]; allData = resolver->GetData(); } if (allData.empty()) { return serviceDataEmptyArray; } JLocal returnData{ env, env->NewObjectArray(allData.size(), serviceDataCls, nullptr)}; for (auto&& data : allData) { JLocal serviceName{env, MakeJString(env, data.serviceName)}; JLocal hostName{env, MakeJString(env, data.hostName)}; wpi::util::SmallVector keysRef; wpi::util::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"