Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add text entries to mDNS service discovery response #19027

Merged
merged 14 commits into from
Jun 3, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,7 @@ public void promptCommissioningSucceeded(int vendorId, int productId, String com
}

public void promptCommissioningFailed(String commissioneeName, String error) {
Log.d(
TAG,
"Received prompt for failure vendor id:"
+ vendorId
+ " productId:"
+ productId
+ ". Commissionee: "
+ commissioneeName);
Log.d(TAG, "Received prompt for failure Commissionee: " + commissioneeName);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(activity, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_baseline_clear_24)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

public class UserPrompterResolver {

private static final String TAG = "UserPrompterResolver";
protected static final String TAG = "UserPrompterResolver";

public native void OnPinCodeEntered(int pinCode);

Expand Down
6 changes: 3 additions & 3 deletions src/platform/android/AndroidChipPlatform-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,11 +238,11 @@ JNI_METHOD(void, nativeSetServiceResolver)(JNIEnv * env, jclass self, jobject re
}

JNI_MDNSCALLBACK_METHOD(void, handleServiceResolve)
(JNIEnv * env, jclass self, jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle,
jlong contextHandle)
(JNIEnv * env, jclass self, jstring instanceName, jstring serviceType, jstring address, jint port, jobject attributes,
jlong callbackHandle, jlong contextHandle)
{
using ::chip::Dnssd::HandleResolve;
HandleResolve(instanceName, serviceType, address, port, callbackHandle, contextHandle);
HandleResolve(instanceName, serviceType, address, port, attributes, callbackHandle, contextHandle);
}

#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
Expand Down
109 changes: 103 additions & 6 deletions src/platform/android/DnssdImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include <cstddef>
#include <jni.h>
#include <memory>
#include <string>

namespace chip {
Expand All @@ -37,11 +38,14 @@ namespace Dnssd {
using namespace chip::Platform;

namespace {
jobject sResolverObject = nullptr;
jobject sMdnsCallbackObject = nullptr;
jmethodID sResolveMethod = nullptr;
jmethodID sPublishMethod = nullptr;
jmethodID sRemoveServicesMethod = nullptr;
jobject sResolverObject = nullptr;
jobject sMdnsCallbackObject = nullptr;
jmethodID sResolveMethod = nullptr;
jmethodID sGetAttributeKeysMethod = nullptr;
jmethodID sGetAttributeDataMethod = nullptr;
jclass sMdnsCallbackClass = nullptr;
jmethodID sPublishMethod = nullptr;
jmethodID sRemoveServicesMethod = nullptr;
} // namespace

// Implementation of functions declared in lib/dnssd/platform/Dnssd.h
Expand Down Expand Up @@ -185,9 +189,14 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject)
sResolverObject = env->NewGlobalRef(resolverObject);
sMdnsCallbackObject = env->NewGlobalRef(mdnsCallbackObject);
jclass resolverClass = env->GetObjectClass(sResolverObject);
sMdnsCallbackClass = env->GetObjectClass(sMdnsCallbackObject);

VerifyOrReturn(resolverClass != nullptr, ChipLogError(Discovery, "Failed to get Resolver Java class"));

sGetAttributeKeysMethod = env->GetMethodID(sMdnsCallbackClass, "getAttributeKeys", "(Ljava/util/Map;)[Ljava/lang/String;");

sGetAttributeDataMethod = env->GetMethodID(sMdnsCallbackClass, "getAttributeData", "(Ljava/util/Map;Ljava/lang/String;)[B");

sResolveMethod =
env->GetMethodID(resolverClass, "resolve", "(Ljava/lang/String;Ljava/lang/String;JJLchip/platform/ChipMdnsCallback;)V");
if (sResolveMethod == nullptr)
Expand All @@ -196,6 +205,18 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject)
env->ExceptionClear();
}

if (sGetAttributeKeysMethod == nullptr)
{
ChipLogError(Discovery, "Failed to access MdnsCallback 'getAttributeKeys' method");
env->ExceptionClear();
}

if (sGetAttributeDataMethod == nullptr)
{
ChipLogError(Discovery, "Failed to access MdnsCallback 'getAttributeData' method");
env->ExceptionClear();
}

sPublishMethod =
env->GetMethodID(resolverClass, "publish",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;[[B[Ljava/lang/String;)V");
Expand All @@ -213,7 +234,26 @@ void InitializeWithObjects(jobject resolverObject, jobject mdnsCallbackObject)
}
}

void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle, jlong contextHandle)
/**
* Helper function which returns the jstring key as a null-terminated char string for the purpose
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
* of constructing the TextEntry list
*/
const char * getTxtInfoKey(JNIEnv * env, jstring key)
{
const char * keyList[] = { "D", "VP", "AP", "CM", "DT", "DN", "RI", "PI", "PH", "CRI", "CRA", "T" };
JniUtfString jniKey(env, key);
for (auto & info : keyList)
{
if (strcmp(info, jniKey.c_str()) == 0)
{
return info;
}
}
return "";
}

void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jobject attributes, jlong callbackHandle,
jlong contextHandle)
{
VerifyOrReturn(callbackHandle != 0, ChipLogError(Discovery, "HandleResolve called with callback equal to nullptr"));

Expand Down Expand Up @@ -243,7 +283,64 @@ void HandleResolve(jstring instanceName, jstring serviceType, jstring address, j
CopyString(service.mType, jniServiceType.c_str());
service.mPort = static_cast<uint16_t>(port);

if (attributes != nullptr)
{
jobjectArray keys = (jobjectArray) env->CallObjectMethod(sMdnsCallbackObject, sGetAttributeKeysMethod, attributes);
size_t size = env->GetArrayLength(keys);
TextEntry * entries = new TextEntry[size];
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
for (size_t i = 0; i < size; i++)
chrisdecenzo marked this conversation as resolved.
Show resolved Hide resolved
{
jstring jniKeyObject = (jstring) env->GetObjectArrayElement(keys, i);
entries[i].mKey = getTxtInfoKey(env, jniKeyObject);
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

jbyteArray datas =
(jbyteArray) env->CallObjectMethod(sMdnsCallbackObject, sGetAttributeDataMethod, attributes, jniKeyObject);
if (datas != nullptr)
{
size_t dataSize = env->GetArrayLength(datas);
uint8_t * data = new uint8_t[dataSize + 1];
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
jbyte * jnidata = env->GetByteArrayElements(datas, nullptr);
for (size_t j = 0; j < dataSize; j++)
{
data[j] = (uint8_t) jnidata[j];
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}
entries[i].mDataSize = dataSize;
entries[i].mData = data;
ChipLogProgress(Discovery, " ----- entry [%u] : %s %s\n", static_cast<unsigned int>(i), entries[i].mKey,
(char *) (entries[i].mData));
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
ChipLogProgress(Discovery, " ----- key=%s", entries[i].mKey);

entries[i].mDataSize = 0;
entries[i].mData = nullptr;
}
}
service.mTextEntrySize = size;
service.mTextEntries = entries;
}
else
{
ChipLogError(Discovery, "attributes is null");
service.mTextEntrySize = 0;
service.mTextEntries = nullptr;
}

dispatch(CHIP_NO_ERROR, &service, &ipAddress);

if (service.mTextEntries != nullptr)
{
size_t size = service.mTextEntrySize;
for (size_t i = 0; i < size; i++)
{
if (service.mTextEntries[i].mData != nullptr)
{
delete[] service.mTextEntries[i].mData;
}
}
delete[] service.mTextEntries;
}
}

} // namespace Dnssd
Expand Down
2 changes: 1 addition & 1 deletion src/platform/android/DnssdImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void InitializeWithObjects(jobject resolverObject, jobject chipMdnsCallbackObjec
/**
* Pass results of the service resolution to the CHIP stack.
*/
void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jlong callbackHandle,
void HandleResolve(jstring instanceName, jstring serviceType, jstring address, jint port, jobject attributes, jlong callbackHandle,
jlong contextHandle);

} // namespace Dnssd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
*/
package chip.platform;

import java.util.Map;

/** Interface for communicating with the CHIP mDNS stack. */
public interface ChipMdnsCallback {
void handleServiceResolve(
String instanceName,
String serviceType,
String address,
int port,
Map<String, byte[]> attributes,
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
long callbackHandle,
long contextHandle);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,23 @@
*/
package chip.platform;

import java.util.Map;

public class ChipMdnsCallbackImpl implements ChipMdnsCallback {
public native void handleServiceResolve(
String instanceName,
String serviceType,
String address,
int port,
Map<String, byte[]> attributes,
long callbackHandle,
long contextHandle);

public String[] getAttributeKeys(Map<String, byte[]> attributes) {
return attributes.keySet().toArray(new String[attributes.size()]);
}

public byte[] getAttributeData(Map<String, byte[]> attributes, String key) {
return attributes.get(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ public void resolve(
NsdServiceInfo serviceInfo = new NsdServiceInfo();
serviceInfo.setServiceName(instanceName);
serviceInfo.setServiceType(serviceType);
Log.d(TAG, "Starting service resolution for '" + instanceName + "'");
Log.d(
TAG,
"resolve: Starting service resolution for '"
+ instanceName
+ "' type '"
+ serviceType
+ "'");

Runnable timeoutRunnable =
new Runnable() {
Expand All @@ -67,6 +73,7 @@ public void run() {
// Ensure we always release the multicast lock. It's possible that we release the
// multicast lock here before ResolveListener returns, but since NsdManager has no API
// to cancel service resolution, there's not much we can do here.
Log.d(TAG, "resolve: Timing out");
if (multicastLock.isHeld()) {
multicastLock.release();
}
Expand All @@ -82,7 +89,7 @@ public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
TAG,
"Failed to resolve service '" + serviceInfo.getServiceName() + "': " + errorCode);
chipMdnsCallback.handleServiceResolve(
instanceName, serviceType, null, 0, callbackHandle, contextHandle);
instanceName, serviceType, null, 0, null, callbackHandle, contextHandle);

if (multicastLock.isHeld()) {
multicastLock.release();
Expand All @@ -104,6 +111,7 @@ public void onServiceResolved(NsdServiceInfo serviceInfo) {
serviceType,
serviceInfo.getHost().getHostAddress(),
serviceInfo.getPort(),
serviceInfo.getAttributes(),
callbackHandle,
contextHandle);

Expand Down