react-native-zeroconf 0.17.3 → 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/NOTICE +2 -6
  2. package/README.md +1 -1
  3. package/android/CMakeLists.txt +64 -0
  4. package/android/build.gradle +1 -17
  5. package/android/generated/java/com/balthazargronon/RCTZeroconf/NativeZeroconfSpec.java +96 -0
  6. package/android/generated/jni/CMakeLists.txt +28 -0
  7. package/android/generated/jni/RNZeroconfSpec-generated.cpp +77 -0
  8. package/android/generated/jni/RNZeroconfSpec.h +31 -0
  9. package/android/generated/jni/react/renderer/components/RNZeroconfSpec/RNZeroconfSpecJSI.h +798 -0
  10. package/android/src/main/java/com/balthazargronon/RCTZeroconf/{ZeroconfModule.java → NsdHost.java} +97 -140
  11. package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPayload.java +87 -0
  12. package/android/src/main/java/com/balthazargronon/RCTZeroconf/NsdPromise.java +40 -0
  13. package/android/src/main/java/com/balthazargronon/RCTZeroconf/Zeroconf.java +4 -6
  14. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfNativeSupport.java +60 -0
  15. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfOptions.java +15 -26
  16. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroconfReactPackage.java +5 -15
  17. package/android/src/main/java/com/balthazargronon/RCTZeroconf/nsd/NsdServiceImpl.java +90 -96
  18. package/android/src/main/jni/mdnsresponder/mDNSShared/dnssd_clientshim.c +31 -6
  19. package/cpp/Backend.cpp +16 -0
  20. package/cpp/Backend.h +116 -0
  21. package/cpp/ZeroconfModule.cpp +280 -0
  22. package/cpp/ZeroconfModule.h +144 -0
  23. package/cpp/android/NsdBackend.cpp +462 -0
  24. package/cpp/android/NsdBackend.h +61 -0
  25. package/cpp/android/ZeroconfAndroidModule.cpp +49 -0
  26. package/cpp/android/ZeroconfAndroidModule.h +15 -0
  27. package/cpp/apple/DispatchExecutor.cpp +66 -0
  28. package/cpp/apple/DispatchExecutor.h +37 -0
  29. package/cpp/apple/LocalNetworkAccess.h +19 -0
  30. package/cpp/apple/LocalNetworkAccess.mm +87 -0
  31. package/cpp/dnssd/DnssdBackend.cpp +976 -0
  32. package/cpp/dnssd/DnssdBackend.h +114 -0
  33. package/cpp/dnssd/Executor.h +28 -0
  34. package/cpp/embedded/EmbeddedExecutor.cpp +124 -0
  35. package/cpp/embedded/EmbeddedExecutor.h +57 -0
  36. package/ios/ZeroconfOnLoad.mm +34 -0
  37. package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec-generated.mm +140 -0
  38. package/ios/generated/ReactCodegen/RNZeroconfSpec/RNZeroconfSpec.h +189 -0
  39. package/ios/generated/ReactCodegen/RNZeroconfSpecJSI.h +798 -0
  40. package/lib/module/NativeZeroconf.js +15 -0
  41. package/lib/module/NativeZeroconf.js.map +1 -0
  42. package/lib/module/bridge.js +124 -0
  43. package/lib/module/bridge.js.map +1 -0
  44. package/{dist → lib/module}/index.js +149 -149
  45. package/lib/module/index.js.map +1 -0
  46. package/lib/module/package.json +1 -0
  47. package/lib/module/types.js +24 -0
  48. package/lib/module/types.js.map +1 -0
  49. package/lib/typescript/package.json +1 -0
  50. package/lib/typescript/src/NativeZeroconf.d.ts +75 -0
  51. package/lib/typescript/src/NativeZeroconf.d.ts.map +1 -0
  52. package/lib/typescript/src/bridge.d.ts +22 -0
  53. package/lib/typescript/src/bridge.d.ts.map +1 -0
  54. package/lib/typescript/src/index.d.ts +111 -0
  55. package/lib/typescript/src/index.d.ts.map +1 -0
  56. package/lib/typescript/src/types.d.ts +175 -0
  57. package/lib/typescript/src/types.d.ts.map +1 -0
  58. package/package.json +64 -29
  59. package/react-native-zeroconf.podspec +2 -1
  60. package/react-native.config.js +17 -0
  61. package/src/NativeZeroconf.ts +120 -0
  62. package/src/bridge.ts +153 -0
  63. package/src/index.ts +607 -0
  64. package/{index.d.ts → src/types.ts} +5 -99
  65. package/windows/RNZeroconf/RNZeroconf.vcxproj +17 -2
  66. package/windows/RNZeroconf/RNZeroconf.vcxproj.filters +0 -6
  67. package/windows/RNZeroconf/ReactPackageProvider.cpp +23 -20
  68. package/windows/RNZeroconf/WindowsBackend.cpp +156 -0
  69. package/windows/RNZeroconf/WindowsBackend.h +13 -0
  70. package/windows/RNZeroconf/ZeroconfCore.cpp +2 -2
  71. package/windows/RNZeroconf/ZeroconfCore.h +2 -2
  72. package/windows/RNZeroconf/ZeroconfWindowsModule.cpp +22 -0
  73. package/windows/RNZeroconf/ZeroconfWindowsModule.h +14 -0
  74. package/android/src/main/java/com/balthazargronon/RCTZeroconf/ZeroConfImplFactory.java +0 -56
  75. package/android/src/main/java/com/balthazargronon/RCTZeroconf/dnssd/DnssdImpl.java +0 -654
  76. package/android/src/main/java/com/github/druk/dnssd/BaseListener.java +0 -33
  77. package/android/src/main/java/com/github/druk/dnssd/BrowseListener.java +0 -67
  78. package/android/src/main/java/com/github/druk/dnssd/DNSRecord.java +0 -47
  79. package/android/src/main/java/com/github/druk/dnssd/DNSSD.java +0 -681
  80. package/android/src/main/java/com/github/druk/dnssd/DNSSDEmbedded.java +0 -198
  81. package/android/src/main/java/com/github/druk/dnssd/DNSSDException.java +0 -66
  82. package/android/src/main/java/com/github/druk/dnssd/DNSSDRecordRegistrar.java +0 -55
  83. package/android/src/main/java/com/github/druk/dnssd/DNSSDRegistration.java +0 -54
  84. package/android/src/main/java/com/github/druk/dnssd/DNSSDService.java +0 -35
  85. package/android/src/main/java/com/github/druk/dnssd/DomainListener.java +0 -57
  86. package/android/src/main/java/com/github/druk/dnssd/InternalBrowseListener.java +0 -76
  87. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSD.java +0 -870
  88. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRecordRegistrar.java +0 -30
  89. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDRegistration.java +0 -34
  90. package/android/src/main/java/com/github/druk/dnssd/InternalDNSSDService.java +0 -29
  91. package/android/src/main/java/com/github/druk/dnssd/InternalDomainListener.java +0 -62
  92. package/android/src/main/java/com/github/druk/dnssd/InternalQueryListener.java +0 -61
  93. package/android/src/main/java/com/github/druk/dnssd/InternalRegisterListener.java +0 -51
  94. package/android/src/main/java/com/github/druk/dnssd/InternalResolveListener.java +0 -58
  95. package/android/src/main/java/com/github/druk/dnssd/NSClass.java +0 -16
  96. package/android/src/main/java/com/github/druk/dnssd/NSType.java +0 -58
  97. package/android/src/main/java/com/github/druk/dnssd/QueryListener.java +0 -54
  98. package/android/src/main/java/com/github/druk/dnssd/RegisterListener.java +0 -46
  99. package/android/src/main/java/com/github/druk/dnssd/RegisterRecordListener.java +0 -35
  100. package/android/src/main/java/com/github/druk/dnssd/ResolveListener.java +0 -55
  101. package/android/src/main/java/com/github/druk/dnssd/TXTRecord.java +0 -293
  102. package/android/src/main/jni/Android.mk +0 -73
  103. package/android/src/main/jni/Application.mk +0 -3
  104. package/android/src/main/jni/DNSSD.java.h +0 -290
  105. package/android/src/main/jni/JNISupport.c +0 -1221
  106. package/ios/RNZeroconf/RNNetServiceSerializer.h +0 -31
  107. package/ios/RNZeroconf/RNNetServiceSerializer.m +0 -84
  108. package/ios/RNZeroconf/RNZeroconf.h +0 -17
  109. package/ios/RNZeroconf/RNZeroconf.m +0 -1025
  110. package/ios/RNZeroconf.xcodeproj/project.pbxproj +0 -261
  111. package/ios/RNZeroconf.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  112. package/src/index.js +0 -563
  113. package/windows/RNZeroconf/RNZeroconf.cpp +0 -228
  114. package/windows/RNZeroconf/RNZeroconf.h +0 -70
@@ -1,654 +0,0 @@
1
- package com.balthazargronon.RCTZeroconf.dnssd;
2
-
3
- import android.annotation.SuppressLint;
4
- import android.content.Context;
5
- import android.net.wifi.WifiManager;
6
- import android.util.Log;
7
-
8
- import com.balthazargronon.RCTZeroconf.Zeroconf;
9
- import com.balthazargronon.RCTZeroconf.ZeroconfModule;
10
- import com.balthazargronon.RCTZeroconf.ZeroconfOptions;
11
- import com.facebook.react.bridge.Promise;
12
- import com.facebook.react.bridge.ReactApplicationContext;
13
- import com.facebook.react.bridge.ReadableArray;
14
- import com.facebook.react.bridge.WritableArray;
15
- import com.facebook.react.bridge.WritableMap;
16
- import com.facebook.react.bridge.WritableNativeArray;
17
- import com.facebook.react.bridge.WritableNativeMap;
18
- import com.github.druk.dnssd.BrowseListener;
19
- import com.github.druk.dnssd.DNSSD;
20
- import com.github.druk.dnssd.DNSSDEmbedded;
21
- import com.github.druk.dnssd.DNSSDException;
22
- import com.github.druk.dnssd.DNSSDRegistration;
23
- import com.github.druk.dnssd.DNSSDService;
24
- import com.github.druk.dnssd.NSClass;
25
- import com.github.druk.dnssd.NSType;
26
- import com.github.druk.dnssd.QueryListener;
27
- import com.github.druk.dnssd.RegisterListener;
28
- import com.github.druk.dnssd.ResolveListener;
29
- import com.github.druk.dnssd.TXTRecord;
30
-
31
- import java.net.InetAddress;
32
- import java.net.UnknownHostException;
33
- import java.util.ArrayList;
34
- import java.util.HashMap;
35
- import java.util.LinkedHashMap;
36
- import java.util.LinkedHashSet;
37
- import java.util.List;
38
- import java.util.Map;
39
- import java.util.Set;
40
- import java.util.concurrent.ExecutorService;
41
- import java.util.concurrent.Executors;
42
-
43
- import javax.annotation.Nullable;
44
-
45
- /**
46
- * Embedded mDNSResponder (dns_sd), the same browse, resolve and address queries as the iOS implementation.
47
- * DNSSD calls can block while the embedded daemon starts, so they and all the state below run on one
48
- * background thread. DNSSD delivers callbacks on the main thread, they are handed back to that thread.
49
- */
50
- public class DnssdImpl implements Zeroconf {
51
- private static final String TAG = "DnssdImpl";
52
-
53
- private final ZeroconfModule zeroconfModule;
54
- private final ReactApplicationContext reactApplicationContext;
55
- private final DNSSD dnssd;
56
- private final ExecutorService executor = Executors.newSingleThreadExecutor();
57
- private final android.os.Handler mainHandler = new android.os.Handler(android.os.Looper.getMainLooper());
58
- private WifiManager.MulticastLock multicastLock;
59
-
60
- // Running scans, keyed by the id of the JS instance that started them
61
- private final Map<String, Scan> scans = new HashMap<>();
62
- // Published services, keyed by the requested name
63
- private final Map<String, Publication> publications = new LinkedHashMap<>();
64
-
65
- private static class Scan {
66
- final String scanId;
67
- final boolean typesOnly;
68
- int ifIndex = DNSSD.ALL_INTERFACES;
69
- long resolveTimeoutMs = 5000;
70
- DNSSDService browse;
71
- // A service is reported once per network interface, count them so found/remove are emitted once
72
- final Map<String, Integer> foundInterfaces = new HashMap<>();
73
- final Map<String, Resolve> resolves = new HashMap<>();
74
-
75
- Scan(String scanId, boolean typesOnly) {
76
- this.scanId = scanId;
77
- this.typesOnly = typesOnly;
78
- }
79
- }
80
-
81
- private static class Resolve {
82
- final String name;
83
- // resolveService(): settled instead of emitting events
84
- @Nullable Promise promise;
85
- final List<DNSSDService> operations = new ArrayList<>();
86
- String fullName;
87
- String host;
88
- int port;
89
- Map<String, String> txt = new LinkedHashMap<>();
90
- final Set<String> addresses = new LinkedHashSet<>();
91
- // Scans: emitted once an address is known, retried once after a timeout
92
- boolean emitted;
93
- boolean retried;
94
-
95
- Resolve(String name) {
96
- this.name = name;
97
- }
98
-
99
- void stop() {
100
- for (DNSSDService operation : operations) {
101
- operation.stop();
102
- }
103
- operations.clear();
104
- }
105
- }
106
-
107
- private static class Publication {
108
- final String requestedName;
109
- final int port;
110
- final Map<String, String> txt;
111
- DNSSDRegistration registration;
112
- @Nullable Promise promise;
113
- String name;
114
- String regType;
115
- String domain;
116
- boolean registered;
117
-
118
- Publication(String requestedName, int port, Map<String, String> txt, @Nullable Promise promise) {
119
- this.requestedName = requestedName;
120
- this.name = requestedName;
121
- this.port = port;
122
- this.txt = txt;
123
- this.promise = promise;
124
- }
125
- }
126
-
127
- public DnssdImpl(ZeroconfModule zeroconfModule, ReactApplicationContext reactApplicationContext) {
128
- this.zeroconfModule = zeroconfModule;
129
- this.reactApplicationContext = reactApplicationContext;
130
- // The embedded mDNSResponder works on every Android version, the system daemon is missing on most devices
131
- this.dnssd = new DNSSDEmbedded(reactApplicationContext);
132
- }
133
-
134
- // Scan
135
-
136
- @Override
137
- public void scan(final String scanId, final String type, final String protocol, final String domain, final ZeroconfOptions options) {
138
- executor.execute(() -> startScan(scanId, type, protocol, domain, options));
139
- }
140
-
141
- private void startScan(String scanId, String type, String protocol, String domain, ZeroconfOptions options) {
142
- stopScan(scanId);
143
-
144
- final Scan scan = new Scan(scanId, ZeroconfModule.isServiceTypesScan(type, protocol));
145
- final int ifIndex = interfaceIndex(options.networkInterface);
146
- if (ifIndex < 0) {
147
- zeroconfModule.sendError(ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_UNKNOWN_INTERFACE, "Unknown network interface " + options.networkInterface, null, scanId);
148
- return;
149
- }
150
- scan.ifIndex = ifIndex;
151
- scan.resolveTimeoutMs = (long) (options.resolveTimeoutSeconds * 1000);
152
- // "_ipp._tcp,_printer" browses the _printer subtype
153
- String regType = String.format("_%s._%s", type, protocol);
154
- if (options.subtype != null) {
155
- regType = ZeroconfOptions.withSubtypes(regType, java.util.Collections.singletonList(options.subtype));
156
- }
157
- Log.d(TAG, "Starting DNSSD scan " + scanId + " for " + regType);
158
- acquireMulticastLock();
159
- try {
160
- scan.browse = dnssd.browse(0, ifIndex, regType, domainOrLocal(domain), new BrowseListener() {
161
- @Override
162
- public void serviceFound(DNSSDService browser, int flags, int ifIndex, String serviceName, String regType, String domain) {
163
- executor.execute(() -> onServiceFound(scan, ifIndex, serviceName, regType, domain));
164
- }
165
-
166
- @Override
167
- public void serviceLost(DNSSDService browser, int flags, int ifIndex, String serviceName, String regType, String domain) {
168
- executor.execute(() -> onServiceLost(scan, serviceName, regType));
169
- }
170
-
171
- @Override
172
- public void operationFailed(DNSSDService service, int errorCode) {
173
- executor.execute(() -> {
174
- if (scans.get(scan.scanId) != scan) {
175
- return;
176
- }
177
- sendError(errorCode, "Browsing services failed: ", null, scan.scanId);
178
- stopScan(scan.scanId);
179
- });
180
- }
181
- });
182
- } catch (DNSSDException e) {
183
- releaseMulticastLock();
184
- sendError(e.getErrorCode(), "Browsing services failed: ", null, scanId);
185
- return;
186
- }
187
- scans.put(scanId, scan);
188
- sendScanEvent(ZeroconfModule.EVENT_START, new WritableNativeMap(), scanId);
189
- }
190
-
191
- private void onServiceFound(Scan scan, int ifIndex, String serviceName, String regType, String domain) {
192
- if (scans.get(scan.scanId) != scan) {
193
- return;
194
- }
195
- String name = scan.typesOnly ? ZeroconfModule.serviceTypeFromResult(serviceName, regType) : serviceName;
196
- Integer count = scan.foundInterfaces.get(name);
197
- scan.foundInterfaces.put(name, count == null ? 1 : count + 1);
198
- if (count != null) {
199
- return;
200
- }
201
- sendScanEvent(ZeroconfModule.EVENT_FOUND, nameToMap(name), scan.scanId);
202
- // Service types are not resolved
203
- if (!scan.typesOnly) {
204
- startResolve(scan, ifIndex, serviceName, regType, domain, null);
205
- }
206
- }
207
-
208
- private void onServiceLost(Scan scan, String serviceName, String regType) {
209
- if (scans.get(scan.scanId) != scan) {
210
- return;
211
- }
212
- String name = scan.typesOnly ? ZeroconfModule.serviceTypeFromResult(serviceName, regType) : serviceName;
213
- Integer count = scan.foundInterfaces.get(name);
214
- if (count == null) {
215
- return;
216
- }
217
- if (count > 1) {
218
- scan.foundInterfaces.put(name, count - 1);
219
- return;
220
- }
221
- scan.foundInterfaces.remove(name);
222
- Resolve resolve = scan.resolves.remove(name);
223
- if (resolve != null) {
224
- resolve.stop();
225
- }
226
- sendScanEvent(ZeroconfModule.EVENT_REMOVE, nameToMap(name), scan.scanId);
227
- }
228
-
229
- @Override
230
- public void stop(final String scanId) {
231
- executor.execute(() -> stopScan(scanId));
232
- }
233
-
234
- @Override
235
- public void stopAll() {
236
- executor.execute(() -> {
237
- for (String scanId : new ArrayList<>(scans.keySet())) {
238
- stopScan(scanId);
239
- }
240
- });
241
- }
242
-
243
- private void stopScan(String scanId) {
244
- Scan scan = scans.remove(scanId);
245
- if (scan == null) {
246
- return;
247
- }
248
- if (scan.browse != null) {
249
- scan.browse.stop();
250
- }
251
- for (Resolve resolve : scan.resolves.values()) {
252
- resolve.stop();
253
- }
254
- scan.resolves.clear();
255
- scan.foundInterfaces.clear();
256
- releaseMulticastLock();
257
- sendScanEvent(ZeroconfModule.EVENT_STOP, new WritableNativeMap(), scanId);
258
- }
259
-
260
- // Resolve: host, port and TXT record, then the host's IPv4 and IPv6 addresses
261
-
262
- private void startResolve(@Nullable final Scan scan, final int ifIndex, final String serviceName, final String regType, final String domain, @Nullable Resolve existing) {
263
- final Resolve resolve = existing != null ? existing : new Resolve(serviceName);
264
- if (scan != null) {
265
- scan.resolves.put(serviceName, resolve);
266
- // DNSSD gives up silently after its own timeout, report it before
267
- mainHandler.postDelayed(() -> executor.execute(() -> {
268
- if (!isCurrent(scan, resolve) || resolve.emitted) {
269
- return;
270
- }
271
- resolve.stop();
272
- // Slow devices can time out, retry once before reporting the error
273
- if (!resolve.retried) {
274
- resolve.retried = true;
275
- startResolve(scan, ifIndex, serviceName, regType, domain, resolve);
276
- return;
277
- }
278
- scan.resolves.remove(serviceName);
279
- zeroconfModule.sendError(ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_TIMEOUT, "Resolving service " + serviceName + " failed: timed out", serviceName, scan.scanId);
280
- }), scan.resolveTimeoutMs);
281
- }
282
- try {
283
- resolve.operations.add(dnssd.resolve(0, ifIndex, serviceName, regType, domain, new ResolveListener() {
284
- @Override
285
- public void serviceResolved(DNSSDService resolver, int flags, int ifIndex, String fullName, String hostName, int port, Map<String, String> txtRecord) {
286
- executor.execute(() -> {
287
- if (!isCurrent(scan, resolve)) {
288
- return;
289
- }
290
- resolve.fullName = fullName;
291
- resolve.host = hostName;
292
- resolve.port = port;
293
- resolve.txt = txtRecord;
294
- queryAddresses(scan, resolve, ifIndex);
295
- });
296
- }
297
-
298
- @Override
299
- public void operationFailed(DNSSDService service, int errorCode) {
300
- executor.execute(() -> onResolveFailed(scan, resolve, errorCode));
301
- }
302
- }));
303
- } catch (DNSSDException e) {
304
- onResolveFailed(scan, resolve, e.getErrorCode());
305
- }
306
- }
307
-
308
- private void queryAddresses(@Nullable final Scan scan, final Resolve resolve, int ifIndex) {
309
- QueryListener listener = new QueryListener() {
310
- @Override
311
- public void queryAnswered(DNSSDService query, int flags, int ifIndex, String fullName, int rrtype, int rrclass, byte[] rdata, int ttl) {
312
- executor.execute(() -> {
313
- if (!isCurrent(scan, resolve)) {
314
- return;
315
- }
316
- try {
317
- resolve.addresses.add(InetAddress.getByAddress(rdata).getHostAddress());
318
- } catch (UnknownHostException e) {
319
- Log.w(TAG, "Invalid address record for " + resolve.host, e);
320
- return;
321
- }
322
- if (scan == null) {
323
- // resolveService() settles with the first address
324
- endSingleResolve(resolve);
325
- resolve.promise.resolve(resolveToMap(resolve));
326
- return;
327
- }
328
- // Emitted for each address, the first one is usable right away
329
- resolve.emitted = true;
330
- sendScanEvent(ZeroconfModule.EVENT_RESOLVE, resolveToMap(resolve), scan.scanId);
331
- });
332
- }
333
-
334
- @Override
335
- public void operationFailed(DNSSDService service, int errorCode) {
336
- executor.execute(() -> onResolveFailed(scan, resolve, errorCode));
337
- }
338
- };
339
- try {
340
- // Each query stops after its first answer, or silently after a timeout (no AAAA record for example)
341
- resolve.operations.add(dnssd.queryRecord(0, ifIndex, resolve.host, NSType.A, NSClass.IN, true, listener));
342
- resolve.operations.add(dnssd.queryRecord(0, ifIndex, resolve.host, NSType.AAAA, NSClass.IN, true, listener));
343
- } catch (DNSSDException e) {
344
- onResolveFailed(scan, resolve, e.getErrorCode());
345
- }
346
- }
347
-
348
- private boolean isCurrent(@Nullable Scan scan, Resolve resolve) {
349
- if (scan == null) {
350
- return singleResolves.contains(resolve);
351
- }
352
- return scans.get(scan.scanId) == scan && scan.resolves.get(resolve.name) == resolve;
353
- }
354
-
355
- private void onResolveFailed(@Nullable Scan scan, Resolve resolve, int errorCode) {
356
- if (!isCurrent(scan, resolve)) {
357
- return;
358
- }
359
- if (scan == null) {
360
- endSingleResolve(resolve);
361
- String message = "Resolving service " + resolve.name + " failed: " + ZeroconfModule.describeDnssdError(errorCode);
362
- ZeroconfModule.reject(resolve.promise, ZeroconfModule.ERROR_DOMAIN_DNSSD, errorCode, message, resolve.name);
363
- return;
364
- }
365
- scan.resolves.remove(resolve.name);
366
- resolve.stop();
367
- sendError(errorCode, "Resolving service " + resolve.name + " failed: ", resolve.name, scan.scanId);
368
- }
369
-
370
- // resolveService(): one service by name, without scanning
371
-
372
- private final Set<Resolve> singleResolves = new LinkedHashSet<>();
373
-
374
- @Override
375
- public void resolveService(final String name, final String type, final String protocol, final String domain, final ZeroconfOptions options, final Promise promise) {
376
- executor.execute(() -> {
377
- int ifIndex = interfaceIndex(options.networkInterface);
378
- if (ifIndex < 0) {
379
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_UNKNOWN_INTERFACE, "Unknown network interface " + options.networkInterface, null);
380
- return;
381
- }
382
- final Resolve resolve = new Resolve(name);
383
- resolve.promise = promise;
384
- singleResolves.add(resolve);
385
- acquireMulticastLock();
386
- startResolve(null, ifIndex, name, String.format("_%s._%s", type, protocol), domainOrLocal(domain), resolve);
387
- // DNSSD gives up silently after its own timeout, settle the promise before
388
- mainHandler.postDelayed(() -> executor.execute(() -> {
389
- if (!singleResolves.contains(resolve)) {
390
- return;
391
- }
392
- endSingleResolve(resolve);
393
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_TIMEOUT, "Resolving service " + name + " failed: timed out", name);
394
- }), (long) (options.timeoutSeconds * 1000));
395
- });
396
- }
397
-
398
- private void endSingleResolve(Resolve resolve) {
399
- if (singleResolves.remove(resolve)) {
400
- resolve.stop();
401
- releaseMulticastLock();
402
- }
403
- }
404
-
405
- // Publish
406
-
407
- @Override
408
- public void registerService(final String type, final String protocol, final String domain, final String name, final int port, final ReadableArray txt, final ZeroconfOptions options, final Promise promise) {
409
- // Read the TXT record on the calling thread, the array belongs to the bridge call
410
- final Map<String, String> txtMap = getTxtRecordMap(txt);
411
- executor.execute(() -> startPublication(type, protocol, domain, name, port, txtMap, options, promise));
412
- }
413
-
414
- private void startPublication(String type, String protocol, String domain, String name, int port, Map<String, String> txt, ZeroconfOptions options, Promise promise) {
415
- int ifIndex = interfaceIndex(options.networkInterface);
416
- if (ifIndex < 0) {
417
- String message = "Unknown network interface " + options.networkInterface;
418
- zeroconfModule.sendError(ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_UNKNOWN_INTERFACE, message, name, null);
419
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_UNKNOWN_INTERFACE, message, name);
420
- return;
421
- }
422
- Publication previous = publications.remove(name);
423
- if (previous != null) {
424
- previous.registration.stop();
425
- }
426
-
427
- final Publication publication = new Publication(name, port, txt, promise);
428
- // "_ipp._tcp,_printer,_color" registers the subtypes too
429
- String regType = ZeroconfOptions.withSubtypes(String.format("_%s._%s", type, protocol), options.subtypes);
430
- try {
431
- publication.registration = dnssd.register(0, ifIndex, name, regType, null, null, port, toTXTRecord(txt), new RegisterListener() {
432
- @Override
433
- public void serviceRegistered(DNSSDRegistration registration, int flags, String serviceName, String regType, String domain) {
434
- executor.execute(() -> onRegistered(publication, serviceName, regType, domain));
435
- }
436
-
437
- @Override
438
- public void operationFailed(DNSSDService service, int errorCode) {
439
- executor.execute(() -> onRegistrationFailed(publication, errorCode));
440
- }
441
- });
442
- } catch (DNSSDException e) {
443
- String prefix = "Registering service " + name + " failed: ";
444
- sendError(e.getErrorCode(), prefix, name, null);
445
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_DNSSD, e.getErrorCode(), prefix + ZeroconfModule.describeDnssdError(e.getErrorCode()), name);
446
- return;
447
- }
448
- publications.put(name, publication);
449
- }
450
-
451
- private void onRegistered(Publication publication, String serviceName, String regType, String domain) {
452
- if (publications.get(publication.requestedName) != publication) {
453
- return;
454
- }
455
- publication.name = serviceName;
456
- publication.regType = regType;
457
- publication.domain = domain;
458
- if (publication.registered) {
459
- return;
460
- }
461
- publication.registered = true;
462
- Log.i(TAG, "Registered service " + serviceName);
463
- zeroconfModule.sendEvent(reactApplicationContext, ZeroconfModule.EVENT_PUBLISHED, publicationToMap(publication));
464
- if (publication.promise != null) {
465
- publication.promise.resolve(publicationToMap(publication));
466
- publication.promise = null;
467
- }
468
- }
469
-
470
- private void onRegistrationFailed(Publication publication, int errorCode) {
471
- if (publications.get(publication.requestedName) != publication) {
472
- return;
473
- }
474
- publications.remove(publication.requestedName);
475
- publication.registration.stop();
476
- String prefix = "Registering service " + publication.requestedName + " failed: ";
477
- sendError(errorCode, prefix, publication.requestedName, null);
478
- ZeroconfModule.reject(publication.promise, ZeroconfModule.ERROR_DOMAIN_DNSSD, errorCode, prefix + ZeroconfModule.describeDnssdError(errorCode), publication.requestedName);
479
- publication.promise = null;
480
- }
481
-
482
- @Override
483
- public void updateService(final String serviceName, final ReadableArray txt, final Promise promise) {
484
- final Map<String, String> txtMap = getTxtRecordMap(txt);
485
- executor.execute(() -> {
486
- Publication publication = findPublication(serviceName);
487
- if (publication == null || !publication.registered) {
488
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_NOT_PUBLISHED, "Service " + serviceName + " is not published", serviceName);
489
- return;
490
- }
491
- try {
492
- publication.registration.getTXTRecord().update(0, toTXTRecord(txtMap).getRawBytes(), 0);
493
- } catch (DNSSDException e) {
494
- String message = "Updating service " + serviceName + " failed: " + ZeroconfModule.describeDnssdError(e.getErrorCode());
495
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_DNSSD, e.getErrorCode(), message, serviceName);
496
- return;
497
- }
498
- publication.txt.clear();
499
- publication.txt.putAll(txtMap);
500
- promise.resolve(publicationToMap(publication));
501
- });
502
- }
503
-
504
- @Nullable
505
- private Publication findPublication(String serviceName) {
506
- // By the requested name, or the name it was published under when it was renamed
507
- Publication publication = publications.get(serviceName);
508
- if (publication == null) {
509
- for (Publication candidate : publications.values()) {
510
- if (candidate.name.equals(serviceName)) {
511
- return candidate;
512
- }
513
- }
514
- }
515
- return publication;
516
- }
517
-
518
- @Override
519
- public void unregisterService(final String serviceName, @Nullable final Promise promise) {
520
- executor.execute(() -> stopPublication(serviceName, promise));
521
- }
522
-
523
- @Override
524
- public void unregisterAllServices() {
525
- executor.execute(() -> {
526
- for (String name : new ArrayList<>(publications.keySet())) {
527
- stopPublication(name, null);
528
- }
529
- });
530
- }
531
-
532
- private void stopPublication(String serviceName, @Nullable Promise promise) {
533
- Publication publication = findPublication(serviceName);
534
- if (publication == null) {
535
- ZeroconfModule.reject(promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_NOT_PUBLISHED, "Service " + serviceName + " is not published", serviceName);
536
- return;
537
- }
538
- publications.remove(publication.requestedName);
539
- // Stopping the registration unregisters synchronously
540
- publication.registration.stop();
541
- if (publication.promise != null) {
542
- ZeroconfModule.reject(publication.promise, ZeroconfModule.ERROR_DOMAIN_LIBRARY, ZeroconfModule.ERROR_CODE_NOT_PUBLISHED, "Service " + serviceName + " was unpublished before it was published", serviceName);
543
- publication.promise = null;
544
- }
545
- WritableMap service = publicationToMap(publication);
546
- if (publication.registered) {
547
- zeroconfModule.sendEvent(reactApplicationContext, ZeroconfModule.EVENT_UNREGISTERED, publicationToMap(publication));
548
- }
549
- if (promise != null) {
550
- promise.resolve(service);
551
- }
552
- }
553
-
554
- // Helpers
555
-
556
- // The index of a network interface by name, DNSSD.ALL_INTERFACES without one, -1 when it doesn't exist
557
- private static int interfaceIndex(@Nullable String networkInterface) {
558
- if (networkInterface == null) {
559
- return DNSSD.ALL_INTERFACES;
560
- }
561
- int index = DNSSD.getIfIndexForName(networkInterface);
562
- return index > 0 ? index : -1;
563
- }
564
-
565
- private static TXTRecord toTXTRecord(Map<String, String> txt) {
566
- TXTRecord txtRecord = new TXTRecord();
567
- for (Map.Entry<String, String> entry : txt.entrySet()) {
568
- txtRecord.set(entry.getKey(), entry.getValue());
569
- }
570
- return txtRecord;
571
- }
572
-
573
- private static String domainOrLocal(@Nullable String domain) {
574
- return domain == null || domain.isEmpty() ? "local." : domain;
575
- }
576
-
577
- private void sendScanEvent(String eventName, WritableMap body, String scanId) {
578
- body.putString(ZeroconfModule.KEY_SCAN_ID, scanId);
579
- zeroconfModule.sendEvent(reactApplicationContext, eventName, body);
580
- }
581
-
582
- private void sendError(int errorCode, String prefix, @Nullable String serviceName, @Nullable String scanId) {
583
- zeroconfModule.sendError(ZeroconfModule.ERROR_DOMAIN_DNSSD, errorCode, prefix + ZeroconfModule.describeDnssdError(errorCode), serviceName, scanId);
584
- }
585
-
586
- private void acquireMulticastLock() {
587
- if (multicastLock == null) {
588
- @SuppressLint("WifiManagerLeak") WifiManager wifi = (WifiManager) reactApplicationContext.getSystemService(Context.WIFI_SERVICE);
589
- multicastLock = wifi.createMulticastLock("multicastLock");
590
- multicastLock.setReferenceCounted(true);
591
- }
592
- multicastLock.acquire();
593
- }
594
-
595
- private void releaseMulticastLock() {
596
- if (multicastLock != null && multicastLock.isHeld()) {
597
- multicastLock.release();
598
- }
599
- }
600
-
601
- private static WritableMap nameToMap(String name) {
602
- WritableMap service = new WritableNativeMap();
603
- service.putString(ZeroconfModule.KEY_SERVICE_NAME, name);
604
- return service;
605
- }
606
-
607
- private static WritableMap resolveToMap(Resolve resolve) {
608
- WritableMap service = new WritableNativeMap();
609
- service.putString(ZeroconfModule.KEY_SERVICE_NAME, resolve.name);
610
- service.putString(ZeroconfModule.KEY_SERVICE_FULL_NAME, resolve.fullName);
611
- service.putString(ZeroconfModule.KEY_SERVICE_HOST, resolve.host);
612
- service.putInt(ZeroconfModule.KEY_SERVICE_PORT, resolve.port);
613
- WritableArray addresses = new WritableNativeArray();
614
- for (String address : resolve.addresses) {
615
- addresses.pushString(address);
616
- }
617
- service.putArray(ZeroconfModule.KEY_SERVICE_ADDRESSES, addresses);
618
- service.putMap(ZeroconfModule.KEY_SERVICE_TXT, txtToMap(resolve.txt));
619
- return service;
620
- }
621
-
622
- private static WritableMap publicationToMap(Publication publication) {
623
- WritableMap service = new WritableNativeMap();
624
- service.putString(ZeroconfModule.KEY_SERVICE_NAME, publication.name);
625
- service.putString(ZeroconfModule.KEY_SERVICE_FULL_NAME, publication.regType != null
626
- ? publication.name + "." + publication.regType + domainOrLocal(publication.domain)
627
- : publication.name);
628
- service.putString(ZeroconfModule.KEY_SERVICE_HOST, publication.name);
629
- service.putInt(ZeroconfModule.KEY_SERVICE_PORT, publication.port);
630
- service.putArray(ZeroconfModule.KEY_SERVICE_ADDRESSES, new WritableNativeArray());
631
- service.putMap(ZeroconfModule.KEY_SERVICE_TXT, txtToMap(publication.txt));
632
- return service;
633
- }
634
-
635
- private static WritableMap txtToMap(@Nullable Map<String, String> txt) {
636
- WritableMap map = new WritableNativeMap();
637
- if (txt != null) {
638
- for (Map.Entry<String, String> entry : txt.entrySet()) {
639
- map.putString(entry.getKey(), entry.getValue() != null ? entry.getValue() : "");
640
- }
641
- }
642
- return map;
643
- }
644
-
645
- private static Map<String, String> getTxtRecordMap(ReadableArray txt) {
646
- // LinkedHashMap keeps the TXT record order
647
- Map<String, String> txtMap = new LinkedHashMap<>();
648
- for (int i = 0; i < txt.size(); i++) {
649
- ReadableArray pair = txt.getArray(i);
650
- txtMap.put(pair.getString(0), pair.getString(1));
651
- }
652
- return txtMap;
653
- }
654
- }
@@ -1,33 +0,0 @@
1
- /*
2
- * Copyright (C) 2016 Andriy Druk
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
-
17
- package com.github.druk.dnssd;
18
-
19
-
20
- /** A base class for DNSSD listeners. */
21
-
22
- public interface BaseListener {
23
- /** Called to report DNSSD operation failures.<P>
24
-
25
- @param service
26
- The service that encountered the failure.
27
- <P>
28
- @param errorCode
29
- Indicates the failure that occurred. See {@link DNSSDException} for error codes.
30
- */
31
- void operationFailed(DNSSDService service, int errorCode);
32
- }
33
-