]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/Java/DNSSD.java
mDNSResponder-66.3.tar.gz
[apple/mdnsresponder.git] / mDNSShared / Java / DNSSD.java
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: DNSSD.java,v $
28 Revision 1.2 2004/05/20 17:43:18 cheshire
29 Fix invalid UTF-8 characters in file
30
31 Revision 1.1 2004/04/30 16:32:34 rpantos
32 First checked in.
33
34
35 This file declares and implements DNSSD, the central Java factory class
36 for doing DNS Service Discovery. It includes the mostly-abstract public
37 interface, as well as the Apple* implementation subclasses.
38
39 To do:
40 - implement network interface mappings
41 - RegisterRecord
42 */
43
44
45 package com.apple.dnssd;
46
47
48 /**
49 DNSSD provides access to DNS Service Discovery features of ZeroConf networking.<P>
50
51 It is a factory class that is used to invoke registration and discovery-related
52 operations. Most operations are non-blocking; clients are called back through an interface
53 with the result of an operation. Callbacks are made from a separate worker thread.<P>
54
55 For example, in this program<P>
56 <PRE><CODE>
57 class MyClient implements BrowseListener {
58 void lookForWebServers() {
59 myBrowser = DNSSD.browse("_http_.tcp", this);
60 }
61
62 public void serviceFound(DNSSDService browser, int flags, int ifIndex,
63 String serviceName, String regType, String domain) {}
64 ...
65 }</CODE></PRE>
66 <CODE>MyClient.serviceFound()</CODE> would be called for every HTTP server discovered in the
67 default browse domain(s).
68 */
69
70 abstract public class DNSSD
71 {
72 /** Flag indicates to a {@link BrowseListener} that another result is
73 queued. Applications should not update their UI to display browse
74 results if the MORE_COMING flag is set; they will be called at least once
75 more with the flag clear.
76 */
77 public static final int MORE_COMING = ( 1 << 0 );
78
79 /** If flag is set in a {@link DomainListener} callback, indicates that the result is the default domain. */
80 public static final int DEFAULT = ( 1 << 2 );
81
82 /** If flag is set, a name conflict will trigger an exception when registering non-shared records.<P>
83 A name must be explicitly specified when registering a service if this bit is set
84 (i.e. the default name may not not be used).
85 */
86 public static final int NO_AUTO_RENAME = ( 1 << 3 );
87
88 /** If flag is set, allow multiple records with this name on the network (e.g. PTR records)
89 when registering individual records on a {@link DNSSDRegistration}.
90 */
91 public static final int SHARED = ( 1 << 4 );
92
93 /** If flag is set, records with this name must be unique on the network (e.g. SRV records). */
94 public static final int UNIQUE = ( 1 << 5 );
95
96 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for browsing. */
97 public static final int BROWSE_DOMAINS = ( 1 << 6 );
98 /** Set flag when calling enumerateDomains() to restrict results to domains recommended for registration. */
99 public static final int REGISTRATION_DOMAINS = ( 1 << 7 );
100
101 /** Maximum length, in bytes, of a domain name represented as an escaped C-String. */
102 public static final int MAX_DOMAIN_NAME = 1005;
103
104 /** Pass for ifIndex to specify all available interfaces. */
105 public static final int ALL_INTERFACES = 0;
106
107 /** Pass for ifIndex to specify the localhost interface. */
108 public static final int LOCALHOST_ONLY = -1;
109
110 /** Browse for instances of a service.<P>
111
112 Note: browsing consumes network bandwidth. Call {@link DNSSDService#stop} when you have finished browsing.<P>
113
114 @param flags
115 Currently ignored, reserved for future use.
116 <P>
117 @param ifIndex
118 If non-zero, specifies the interface on which to browse for services
119 (the index for a given interface is determined via the if_nametoindex()
120 family of calls.) Most applications will pass 0 to browse on all available
121 interfaces. Pass -1 to only browse for services provided on the local host.
122 <P>
123 @param regType
124 The registration type being browsed for followed by the protocol, separated by a
125 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
126 <P>
127 @param domain
128 If non-null, specifies the domain on which to browse for services.
129 Most applications will not specify a domain, instead browsing on the
130 default domain(s).
131 <P>
132 @param listener
133 This object will get called when instances of the service are discovered (or disappear).
134 <P>
135 @return A {@link DNSSDService} that represents the active browse operation.
136
137 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
138 @see RuntimePermission
139 */
140 public static DNSSDService browse( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
141 throws DNSSDException
142 { return getInstance()._makeBrowser( flags, ifIndex, regType, domain, listener); }
143
144 /** Browse for instances of a service. Use default flags, ifIndex and domain.<P>
145
146 @param regType
147 The registration type being browsed for followed by the protocol, separated by a
148 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
149 <P>
150 @param listener
151 This object will get called when instances of the service are discovered (or disappear).
152 <P>
153 @return A {@link DNSSDService} that represents the active browse operation.
154
155 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
156 @see RuntimePermission
157 */
158 public static DNSSDService browse( String regType, BrowseListener listener)
159 throws DNSSDException
160 { return browse( 0, 0, regType, "", listener); }
161
162 /** Resolve a service name discovered via browse() to a target host name, port number, and txt record.<P>
163
164 Note: Applications should NOT use resolve() solely for txt record monitoring - use
165 queryRecord() instead, as it is more efficient for this task.<P>
166
167 Note: When the desired results have been returned, the client MUST terminate the resolve by
168 calling {@link DNSSDService#stop}.<P>
169
170 Note: resolve() behaves correctly for typical services that have a single SRV record and
171 a single TXT record (the TXT record may be empty.) To resolve non-standard services with
172 multiple SRV or TXT records, use queryRecord().<P>
173
174 @param flags
175 Currently ignored, reserved for future use.
176 <P>
177 @param ifIndex
178 The interface on which to resolve the service. The client should
179 pass the interface on which the serviceName was discovered (i.e.
180 the ifIndex passed to the serviceFound() callback)
181 or 0 to resolve the named service on all available interfaces.
182 <P>
183 @param serviceName
184 The servicename to be resolved.
185 <P>
186 @param regType
187 The registration type being resolved followed by the protocol, separated by a
188 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
189 <P>
190 @param domain
191 The domain on which the service is registered, i.e. the domain passed
192 to the serviceFound() callback.
193 <P>
194 @param listener
195 This object will get called when the service is resolved.
196 <P>
197 @return A {@link DNSSDService} that represents the active resolve operation.
198
199 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
200 @see RuntimePermission
201 */
202 public static DNSSDService resolve( int flags, int ifIndex, String serviceName, String regType,
203 String domain, ResolveListener listener)
204 throws DNSSDException
205 { return getInstance()._resolve( flags, ifIndex, serviceName, regType, domain, listener); }
206
207 /** Register a service, to be discovered via browse() and resolve() calls.<P>
208 @param flags
209 Possible values are: NO_AUTO_RENAME.
210 <P>
211 @param ifIndex
212 If non-zero, specifies the interface on which to register the service
213 (the index for a given interface is determined via the if_nametoindex()
214 family of calls.) Most applications will pass 0 to register on all
215 available interfaces. Pass -1 to register a service only on the local
216 machine (service will not be visible to remote hosts).
217 <P>
218 @param serviceName
219 If non-null, specifies the service name to be registered.
220 Applications need not specify a name, in which case the
221 computer name is used (this name is communicated to the client via
222 the serviceRegistered() callback).
223 <P>
224 @param regType
225 The registration type being registered followed by the protocol, separated by a
226 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
227 <P>
228 @param domain
229 If non-null, specifies the domain on which to advertise the service.
230 Most applications will not specify a domain, instead automatically
231 registering in the default domain(s).
232 <P>
233 @param host
234 If non-null, specifies the SRV target host name. Most applications
235 will not specify a host, instead automatically using the machine's
236 default host name(s). Note that specifying a non-null host does NOT
237 create an address record for that host - the application is responsible
238 for ensuring that the appropriate address record exists, or creating it
239 via {@link DNSSDRegistration#addRecord}.
240 <P>
241 @param port
242 The port on which the service accepts connections. Pass 0 for a
243 "placeholder" service (i.e. a service that will not be discovered by
244 browsing, but will cause a name conflict if another client tries to
245 register that same name.) Most clients will not use placeholder services.
246 <P>
247 @param txtRecord
248 The txt record rdata. May be null. Note that a non-null txtRecord
249 MUST be a properly formatted DNS TXT record, i.e. &lt;length byte&gt; &lt;data&gt;
250 &lt;length byte&gt; &lt;data&gt; ...
251 <P>
252 @param listener
253 This object will get called when the service is registered.
254 <P>
255 @return A {@link DNSSDRegistration} that controls the active registration.
256
257 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
258 @see RuntimePermission
259 */
260 public static DNSSDRegistration register( int flags, int ifIndex, String serviceName, String regType,
261 String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
262 throws DNSSDException
263 { return getInstance()._register( flags, ifIndex, serviceName, regType, domain, host, port, txtRecord, listener); }
264
265 /** Register a service, to be discovered via browse() and resolve() calls. Use default flags, ifIndex, domain, host and txtRecord.<P>
266 @param serviceName
267 If non-null, specifies the service name to be registered.
268 Applications need not specify a name, in which case the
269 computer name is used (this name is communicated to the client via
270 the serviceRegistered() callback).
271 <P>
272 @param regType
273 The registration type being registered followed by the protocol, separated by a
274 dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
275 <P>
276 @param port
277 The port on which the service accepts connections. Pass 0 for a
278 "placeholder" service (i.e. a service that will not be discovered by
279 browsing, but will cause a name conflict if another client tries to
280 register that same name.) Most clients will not use placeholder services.
281 <P>
282 @param listener
283 This object will get called when the service is registered.
284 <P>
285 @return A {@link DNSSDRegistration} that controls the active registration.
286
287 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
288 @see RuntimePermission
289 */
290 public static DNSSDRegistration register( String serviceName, String regType, int port, RegisterListener listener)
291 throws DNSSDException
292 { return register( 0, 0, serviceName, regType, null, null, port, null, listener); }
293
294 /** Query for an arbitrary DNS record.<P>
295 @param flags
296 Possible values are: MORE_COMING.
297 <P>
298 @param ifIndex
299 If non-zero, specifies the interface on which to issue the query
300 (the index for a given interface is determined via the if_nametoindex()
301 family of calls.) Passing 0 causes the name to be queried for on all
302 interfaces. Passing -1 causes the name to be queried for only on the
303 local host.
304 <P>
305 @param serviceName
306 The full domain name of the resource record to be queried for.
307 <P>
308 @param rrtype
309 The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
310 as defined in nameser.h.
311 <P>
312 @param rrclass
313 The class of the resource record, as defined in nameser.h
314 (usually 1 for the Internet class).
315 <P>
316 @param listener
317 This object will get called when the query completes.
318 <P>
319 @return A {@link DNSSDService} that controls the active query.
320
321 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
322 @see RuntimePermission
323 */
324 public static DNSSDService queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
325 int rrclass, QueryListener listener)
326 throws DNSSDException
327 { return getInstance()._queryRecord( flags, ifIndex, serviceName, rrtype, rrclass, listener); }
328
329 /** Asynchronously enumerate domains available for browsing and registration.<P>
330
331 Currently, the only domain returned is "local.", but other domains will be returned in future.<P>
332
333 The enumeration MUST be cancelled by calling {@link DNSSDService#stop} when no more domains
334 are to be found.<P>
335 @param flags
336 Possible values are: BROWSE_DOMAINS, REGISTRATION_DOMAINS.
337 <P>
338 @param ifIndex
339 If non-zero, specifies the interface on which to look for domains.
340 (the index for a given interface is determined via the if_nametoindex()
341 family of calls.) Most applications will pass 0 to enumerate domains on
342 all interfaces.
343 <P>
344 @param listener
345 This object will get called when domains are found.
346 <P>
347 @return A {@link DNSSDService} that controls the active enumeration.
348
349 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
350 @see RuntimePermission
351 */
352 public static DNSSDService enumerateDomains( int flags, int ifIndex, DomainListener listener)
353 throws DNSSDException
354 { return getInstance()._enumerateDomains( flags, ifIndex, listener); }
355
356 /** Concatenate a three-part domain name (as provided to the listeners) into a
357 properly-escaped full domain name. Note that strings passed to listeners are
358 ALREADY ESCAPED where necessary.<P>
359 @param serviceName
360 The service name - any dots or slashes must NOT be escaped.
361 May be null (to construct a PTR record name, e.g. "_ftp._tcp.apple.com").
362 <P>
363 @param regType
364 The registration type followed by the protocol, separated by a dot (e.g. "_ftp._tcp").
365 <P>
366 @param domain
367 The domain name, e.g. "apple.com". Any literal dots or backslashes must be escaped.
368 <P>
369 @return The full domain name.
370
371 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
372 @see RuntimePermission
373 */
374 public static String constructFullName( String serviceName, String regType, String domain)
375 throws DNSSDException
376 { return getInstance()._constructFullName( serviceName, regType, domain); }
377
378 /** Instruct the daemon to verify the validity of a resource record that appears to
379 be out of date. (e.g. because tcp connection to a service's target failed.) <P>
380
381 Causes the record to be flushed from the daemon's cache (as well as all other
382 daemons' caches on the network) if the record is determined to be invalid.<P>
383 @param flags
384 Currently unused, reserved for future use.
385 <P>
386 @param ifIndex
387 If non-zero, specifies the interface on which to reconfirm the record
388 (the index for a given interface is determined via the if_nametoindex()
389 family of calls.) Passing 0 causes the name to be reconfirmed on all
390 interfaces. Passing -1 causes the name to be reconfirmed only on the
391 local host.
392 <P>
393 @param fullName
394 The resource record's full domain name.
395 <P>
396 @param rrtype
397 The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
398 <P>
399 @param rrclass
400 The class of the resource record, as defined in nameser.h (usually 1).
401 <P>
402 @param rdata
403 The raw rdata of the resource record.
404
405 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
406 @see RuntimePermission
407 */
408 public static void reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
409 int rrclass, byte[] rdata)
410 { getInstance()._reconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata); }
411
412 /** Return the canonical name of a particular interface index.<P>
413 @param ifIndex
414 A valid interface index. Must not be ALL_INTERFACES.
415 <P>
416 @return The name of the interface, which should match java.net.NetworkInterface.getName().
417
418 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
419 @see RuntimePermission
420 */
421 public static String getNameForIfIndex( int ifIndex)
422 { return getInstance()._getNameForIfIndex( ifIndex); }
423
424 /** Return the index of a named interface.<P>
425 @param ifName
426 A valid interface name. An example is java.net.NetworkInterface.getName().
427 <P>
428 @return The interface index.
429
430 @throws SecurityException If a security manager is present and denies <tt>RuntimePermission("getDNSSDInstance")</tt>.
431 @see RuntimePermission
432 */
433 public static int getIfIndexForName( String ifName)
434 { return getInstance()._getIfIndexForName( ifName); }
435
436 protected DNSSD() {} // prevent direct instantiation
437
438 /** Return the single instance of DNSSD. */
439 static protected final DNSSD getInstance()
440 {
441 SecurityManager sm = System.getSecurityManager();
442 if ( sm != null)
443 sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
444 return fInstance;
445 }
446
447 abstract protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener listener)
448 throws DNSSDException;
449
450 abstract protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
451 String domain, ResolveListener listener)
452 throws DNSSDException;
453
454 abstract protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
455 String domain, String host, int port, TXTRecord txtRecord, RegisterListener listener)
456 throws DNSSDException;
457
458 abstract protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
459 int rrclass, QueryListener listener)
460 throws DNSSDException;
461
462 abstract protected DNSSDService _enumerateDomains( int flags, int ifIndex, DomainListener listener)
463 throws DNSSDException;
464
465 abstract protected String _constructFullName( String serviceName, String regType, String domain)
466 throws DNSSDException;
467
468 abstract protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
469 int rrclass, byte[] rdata);
470
471 abstract protected String _getNameForIfIndex( int ifIndex);
472
473 abstract protected int _getIfIndexForName( String ifName);
474
475 protected static DNSSD fInstance;
476
477 static
478 {
479 try
480 {
481 String name = System.getProperty( "com.apple.dnssd.DNSSD" );
482 if( name == null )
483 name = "com.apple.dnssd.AppleDNSSD"; // Fall back to Apple-provided class.
484 fInstance = (DNSSD) Class.forName( name ).newInstance();
485 }
486 catch( Exception e )
487 {
488 throw new InternalError( "cannot instantiate DNSSD" + e );
489 }
490 }
491 }
492
493
494 // Concrete implementation of DNSSDException
495 class AppleDNSSDException extends DNSSDException
496 {
497 public AppleDNSSDException( int errorCode) { fErrorCode = errorCode; }
498
499 public int getErrorCode() { return fErrorCode; }
500
501 public String getMessage()
502 {
503 final String kMessages[] = { // should probably be put into a resource or something
504 "UNKNOWN",
505 "NO_SUCH_NAME",
506 "NO_MEMORY",
507 "BAD_PARAM",
508 "BAD_REFERENCE",
509 "BAD_STATE",
510 "BAD_FLAGS",
511 "UNSUPPORTED",
512 "NOT_INITIALIZED",
513 "", // there is NO number 6
514 "ALREADY_REGISTERED",
515 "NAME_CONFLICT",
516 "INVALID",
517 "", // another MIA
518 "INCOMPATIBLE",
519 "BAD_INTERFACE_INDEX"
520 };
521
522 if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
523 {
524 return "DNS-SD Error " + String.valueOf( fErrorCode) + ": " + kMessages[ UNKNOWN - fErrorCode];
525 }
526 else
527 return super.getMessage() + "(" + String.valueOf( fErrorCode) + ")";
528 }
529
530 protected int fErrorCode;
531 }
532
533 // The concrete, default implementation.
534 class AppleDNSSD extends DNSSD
535 {
536 static
537 {
538 System.loadLibrary( "jdns_sd");
539
540 int libInitResult = InitLibrary( 1);
541
542 if ( libInitResult != DNSSDException.NO_ERROR)
543 throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
544 }
545
546 static public boolean hasAutoCallbacks; // Set by InitLibrary() to value of AUTO_CALLBACKS
547
548 protected DNSSDService _makeBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
549 throws DNSSDException
550 {
551 return new AppleBrowser( flags, ifIndex, regType, domain, client);
552 }
553
554 protected DNSSDService _resolve( int flags, int ifIndex, String serviceName, String regType,
555 String domain, ResolveListener client)
556 throws DNSSDException
557 {
558 return new AppleResolver( flags, ifIndex, serviceName, regType, domain, client);
559 }
560
561 protected DNSSDRegistration _register( int flags, int ifIndex, String serviceName, String regType,
562 String domain, String host, int port, TXTRecord txtRecord, RegisterListener client)
563 throws DNSSDException
564 {
565 return new AppleRegistration( flags, ifIndex, serviceName, regType, domain, host, port,
566 ( txtRecord != null) ? txtRecord.getRawBytes() : null, client);
567 }
568
569 protected DNSSDService _queryRecord( int flags, int ifIndex, String serviceName, int rrtype,
570 int rrclass, QueryListener client)
571 throws DNSSDException
572 {
573 return new AppleQuery( flags, ifIndex, serviceName, rrtype, rrclass, client);
574 }
575
576 protected DNSSDService _enumerateDomains( int flags, int ifIndex, DomainListener listener)
577 throws DNSSDException
578 {
579 return new AppleDomainEnum( flags, ifIndex, listener);
580 }
581
582 protected String _constructFullName( String serviceName, String regType, String domain)
583 throws DNSSDException
584 {
585 String[] responseHolder = new String[1]; // lame maneuver to get around Java's lack of reference parameters
586
587 int rc = ConstructName( serviceName, regType, domain, responseHolder);
588 if ( rc != 0)
589 throw new AppleDNSSDException( rc);
590
591 return responseHolder[0];
592 }
593
594 protected void _reconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
595 int rrclass, byte[] rdata)
596 {
597 ReconfirmRecord( flags, ifIndex, fullName, rrtype, rrclass, rdata);
598 }
599
600 protected String _getNameForIfIndex( int ifIndex)
601 {
602 return null; // ••Fix me - RNP
603 }
604
605 protected int _getIfIndexForName( String ifName)
606 {
607 return 0; // ••Fix me - RNP
608 }
609
610
611 protected native int ConstructName( String serviceName, String regType, String domain, String[] pOut);
612
613 protected native void ReconfirmRecord( int flags, int ifIndex, String fullName, int rrtype,
614 int rrclass, byte[] rdata);
615
616 protected static native int InitLibrary( int callerVersion);
617 }
618
619 class AppleService implements DNSSDService, Runnable
620 {
621 public AppleService() { fNativeContext = 0; }
622
623 public void stop() { this.HaltOperation(); }
624
625 public void finalize() throws Throwable
626 {
627 this.stop();
628 super.finalize();
629 }
630
631 /* The run() method is used internally to schedule an update from another thread */
632 public void run()
633 {
634 this.ProcessResults();
635 }
636
637 /* Block for timeout ms (or forever if -1). Returns 1 if data present, 0 if timed out, -1 if not browsing. */
638 protected native int BlockForData( int msTimeout);
639
640 /* Call ProcessResults when data appears on socket descriptor. */
641 protected native void ProcessResults();
642
643 protected native void HaltOperation();
644
645 protected void ThrowOnErr( int rc) throws DNSSDException
646 {
647 if ( rc != 0)
648 throw new AppleDNSSDException( rc);
649 }
650
651 protected int /* warning */ fNativeContext; // Private storage for native side
652 }
653
654
655 // A ServiceThread calls AppleService.BlockForData() and schedules its client
656 // when data appears.
657 class ServiceThread extends Thread
658 {
659 public ServiceThread( AppleService owner) { fOwner = owner; }
660
661 public void run()
662 {
663 int result;
664
665 while ( true )
666 {
667 result = fOwner.BlockForData( -1);
668 if ( result == 1)
669 {
670 fOwner.run();
671 }
672 else
673 break; // terminate thread
674 }
675 }
676
677 protected AppleService fOwner;
678 }
679
680
681 class AppleBrowser extends AppleService
682 {
683 public AppleBrowser( int flags, int ifIndex, String regType, String domain, BrowseListener client)
684 throws DNSSDException
685 {
686 fClient = client;
687 this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
688 if ( !AppleDNSSD.hasAutoCallbacks)
689 new ServiceThread( this).start();
690 }
691
692 // Sets fNativeContext. Returns non-zero on error.
693 protected native int CreateBrowser( int flags, int ifIndex, String regType, String domain);
694
695 protected BrowseListener fClient;
696 }
697
698 class AppleResolver extends AppleService
699 {
700 public AppleResolver( int flags, int ifIndex, String serviceName, String regType,
701 String domain, ResolveListener client)
702 throws DNSSDException
703 {
704 fClient = client;
705 this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
706 if ( !AppleDNSSD.hasAutoCallbacks)
707 new ServiceThread( this).start();
708 }
709
710 // Sets fNativeContext. Returns non-zero on error.
711 protected native int CreateResolver( int flags, int ifIndex, String serviceName, String regType,
712 String domain);
713
714 protected ResolveListener fClient;
715 }
716
717 // An AppleDNSRecord is a simple wrapper around a dns_sd DNSRecord.
718 class AppleDNSRecord extends DNSRecord
719 {
720 public int fRecord; // Really a DNSRecord; sizeof(int) == sizeof(void*) ?
721 }
722
723 class AppleRegistration extends AppleService implements DNSSDRegistration
724 {
725 public AppleRegistration( int flags, int ifIndex, String serviceName, String regType, String domain,
726 String host, int port, byte[] txtRecord, RegisterListener client)
727 throws DNSSDException
728 {
729 fClient = client;
730 this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
731 if ( !AppleDNSSD.hasAutoCallbacks)
732 new ServiceThread( this).start();
733 }
734
735 public DNSRecord addRecord( int flags, int rrType, byte[] rData, int ttl)
736 throws DNSSDException
737 {
738 AppleDNSRecord newRecord = new AppleDNSRecord();
739
740 this.ThrowOnErr( this.AddRecord( flags, rrType, rData, ttl, newRecord));
741
742 return newRecord;
743 }
744
745 public void updateRecord( DNSRecord record, int flags, byte[] rData, int ttl)
746 throws DNSSDException
747 {
748 this.ThrowOnErr( this.UpdateRecord( (AppleDNSRecord) record, flags, rData, ttl));
749 }
750
751 public void removeRecord( DNSRecord record, int flags)
752 throws DNSSDException
753 {
754 this.ThrowOnErr( this.RemoveRecord( (AppleDNSRecord) record, flags));
755 }
756
757 // Sets fNativeContext. Returns non-zero on error.
758 protected native int BeginRegister( int ifIndex, int flags, String serviceName, String regType,
759 String domain, String host, int port, byte[] txtRecord);
760
761 // Sets fNativeContext. Returns non-zero on error.
762 protected native int AddRecord( int flags, int rrType, byte[] rData, int ttl, AppleDNSRecord destObj);
763
764 protected native int UpdateRecord( AppleDNSRecord destObj, int flags, byte[] rData, int ttl);
765
766 protected native int RemoveRecord( AppleDNSRecord destObj, int flags);
767
768 protected RegisterListener fClient;
769 }
770
771 class AppleQuery extends AppleService
772 {
773 public AppleQuery( int flags, int ifIndex, String serviceName, int rrtype,
774 int rrclass, QueryListener client)
775 throws DNSSDException
776 {
777 fClient = client;
778 this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
779 if ( !AppleDNSSD.hasAutoCallbacks)
780 new ServiceThread( this).start();
781 }
782
783 // Sets fNativeContext. Returns non-zero on error.
784 protected native int CreateQuery( int flags, int ifIndex, String serviceName, int rrtype, int rrclass);
785
786 protected QueryListener fClient;
787 }
788
789 class AppleDomainEnum extends AppleService
790 {
791 public AppleDomainEnum( int flags, int ifIndex, DomainListener listener)
792 throws DNSSDException
793 {
794 fClient = listener;
795 this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
796 if ( !AppleDNSSD.hasAutoCallbacks)
797 new ServiceThread( this).start();
798 }
799
800 // Sets fNativeContext. Returns non-zero on error.
801 protected native int BeginEnum( int flags, int ifIndex);
802
803 protected DomainListener fClient;
804 }
805
806